diff --git a/aspnet-core/.gitignore b/aspnet-core/.gitignore index a7eaf8aeb..662fca440 100644 --- a/aspnet-core/.gitignore +++ b/aspnet-core/.gitignore @@ -4,5 +4,4 @@ LocalNuget **/*.csproj.user nupkg consoles -templates *.configs.cache \ No newline at end of file diff --git a/aspnet-core/templates/.gitignore b/aspnet-core/templates/.gitignore new file mode 100644 index 000000000..d327b6024 --- /dev/null +++ b/aspnet-core/templates/.gitignore @@ -0,0 +1,9 @@ +.vs +LocalNuget +*.DotSettings.user +**/*.csproj.user +nupkg +consoles +*.configs.cache +*.nupkg +*.nuspec \ No newline at end of file diff --git a/aspnet-core/templates/content/.template.config/template.json b/aspnet-core/templates/content/.template.config/template.json new file mode 100644 index 000000000..8ba44d248 --- /dev/null +++ b/aspnet-core/templates/content/.template.config/template.json @@ -0,0 +1,99 @@ +{ + "$schema": "http://json.schemastore.org/template", + "author": "colin.in@foxmail.com", + "classifications": [ "micro", "webapi", "cloud" ], + "name": "LINGYUN.Abp.MicroService", + "identity": "LINGYUN.Abp.MicroService", //模板唯一标识 + "groupIdentity": "LINGYUN.Abp.Application", + "shortName": "lam", + "tags": { + "language": "C#", + "type": "project" + }, + "sourceName": "ProjectName", + "preferNameDirectory": true, + "symbols": { + "AuthenticationScheme": { + "type": "parameter", + "description": "Authentication Scheme", + "datatype": "choice", + "defaultValue": "IdentityServer4", + "isRequired": false, + "choices": [ + { + "choice": "IdentityServer4", + "description": "IdentityServer4" + }, + { + "choice": "OpenIddict", + "description": "OpenIddict" + } + ] + }, + "DatabaseManagement": { + "type": "parameter", + "description": "Database Management", + "dataType": "choice", + "defaultValue": "MySQL", + "isRequired": false, + "choices": [ + { + "choice": "SqlServer", + "description": "Sql Server" + }, + { + "choice": "MySQL", + "description": "My SQL" + }, + { + "choice": "Sqlite", + "description": "Sqlite" + }, + { + "choice": "Oracle", + "description": "Oracle" + }, + { + "choice": "OracleDevart", + "description": "Oracle Devart Driver" + }, + { + "choice": "PostgreSql", + "description": "Postgre Sql" + } + ] + }, + "SqlServer": { + "type": "computed", + "value": "(DatabaseManagement == \"SqlServer\")" + }, + "MySQL": { + "type": "computed", + "value": "(DatabaseManagement == \"MySQL\")" + }, + "Sqlite": { + "type": "computed", + "value": "(DatabaseManagement == \"Sqlite\")" + }, + "Oracle": { + "type": "computed", + "value": "(DatabaseManagement == \"Oracle\")" + }, + "OracleDevart": { + "type": "computed", + "value": "(DatabaseManagement == \"Oracle.Devart\")" + }, + "PostgreSql": { + "type": "computed", + "value": "(DatabaseManagement == \"PostgreSql\")" + }, + "IdentityServer4": { + "type": "computed", + "value": "(AuthenticationScheme == \"IdentityServer4\")" + }, + "OpenIddict": { + "type": "computed", + "value": "(AuthenticationScheme == \"OpenIddict\")" + } + } +} \ No newline at end of file diff --git a/aspnet-core/templates/content/Directory.Build.props b/aspnet-core/templates/content/Directory.Build.props new file mode 100644 index 000000000..39b252a30 --- /dev/null +++ b/aspnet-core/templates/content/Directory.Build.props @@ -0,0 +1,33 @@ + + + 1.6.9 + 7.0.2 + 7.0.2 + 7.0.3 + 1.10.0 + 1.0.2 + 1.0.0-rc8 + 1.3.1 + 1.0.0-rc8 + 1.0.0-rc8 + 1.0.0-beta2 + 2.10.0 + 1.5.0 + 5.0.0 + 2.2.0 + 2.0.0 + 2.0.1 + 3.1.0 + 3.0.1 + 3.4.0 + 4.0.0 + 8.4.1 + 5.0.0 + 6.1.5 + 7.0.* + 7.0.2 + 2.4.1 + 3.0.2 + 4.2.1 + + \ No newline at end of file diff --git a/aspnet-core/templates/content/common.props b/aspnet-core/templates/content/common.props new file mode 100644 index 000000000..413528f92 --- /dev/null +++ b/aspnet-core/templates/content/common.props @@ -0,0 +1,36 @@ + + + latest + 7.0.2 + colin + $(NoWarn);CS1591;CS0436 + https://github.com/colinin/abp-next-admin + MIT + git + https://github.com/colinin/abp-next-admin + true + + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)LocalNuget + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/configureawait.props b/aspnet-core/templates/content/configureawait.props new file mode 100644 index 000000000..92f22f85f --- /dev/null +++ b/aspnet-core/templates/content/configureawait.props @@ -0,0 +1,9 @@ + + + + + All + runtime; build; native; contentfiles; analyzers + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/DbMigratorHostedService.cs b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/DbMigratorHostedService.cs new file mode 100644 index 000000000..b61e0dc04 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/DbMigratorHostedService.cs @@ -0,0 +1,49 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore; +using Serilog; +using Volo.Abp; + +namespace PackageName.CompanyName.ProjectName.DbMigrator; + +public class DbMigratorHostedService : IHostedService +{ + private readonly IHostApplicationLifetime _hostApplicationLifetime; + private readonly IConfiguration _configuration; + + public DbMigratorHostedService( + IHostApplicationLifetime hostApplicationLifetime, + IConfiguration configuration) + { + _hostApplicationLifetime = hostApplicationLifetime; + _configuration = configuration; + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + using var application = await AbpApplicationFactory + .CreateAsync(options => + { + options.Services.ReplaceConfiguration(_configuration); + options.UseAutofac(); + options.Services.AddLogging(c => c.AddSerilog()); + }); + await application.InitializeAsync(); + + await application + .ServiceProvider + .GetRequiredService() + .MigrateAsync(); + + await application.ShutdownAsync(); + + _hostApplicationLifetime.StopApplication(); + } + + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; + } +} + diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/FodyWeavers.xml b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/FodyWeavers.xsd b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/PackageName.CompanyName.ProjectName.DbMigrator.csproj b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/PackageName.CompanyName.ProjectName.DbMigrator.csproj new file mode 100644 index 000000000..5f46df834 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/PackageName.CompanyName.ProjectName.DbMigrator.csproj @@ -0,0 +1,44 @@ + + + + + + + Exe + net7.0 + enable + enable + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/PackageNameCompanyNameProjectNameDbMigratorModule.cs b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/PackageNameCompanyNameProjectNameDbMigratorModule.cs new file mode 100644 index 000000000..18b109f71 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/PackageNameCompanyNameProjectNameDbMigratorModule.cs @@ -0,0 +1,13 @@ +using PackageName.CompanyName.ProjectName.EntityFrameworkCore; +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace PackageName.CompanyName.ProjectName.DbMigrator; + +[DependsOn( + typeof(AbpAutofacModule), + typeof(ProjectNameEntityFrameworkCoreModule) + )] +public class PackageNameCompanyNameProjectNameDbMigratorModule : AbpModule +{ +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/Program.cs b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/Program.cs new file mode 100644 index 000000000..8f6151dfe --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/Program.cs @@ -0,0 +1,40 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Serilog; +using Serilog.Events; + +namespace PackageName.CompanyName.ProjectName.DbMigrator; + +public class Program +{ + public async static Task Main(string[] args) + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Information() + .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) + .MinimumLevel.Override("Volo.Abp", LogEventLevel.Warning) +#if DEBUG + .MinimumLevel.Override("PackageName.CompanyName.ProjectName", LogEventLevel.Debug) +#else + .MinimumLevel.Override("PackageName.CompanyName.ProjectName", LogEventLevel.Information) +#endif + .Enrich.FromLogContext() + .WriteTo.Async(c => c.File("Logs/logs.txt")) + .WriteTo.Async(c => c.Console()) + .CreateLogger(); + + await CreateHostBuilder(args).RunConsoleAsync(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .AddAppSettingsSecretsJson() + .ConfigureLogging((context, logging) => logging.ClearProviders()) + .ConfigureServices((hostContext, services) => + { + services.AddHostedService(); + }); + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.Development.json b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.Development.json new file mode 100644 index 000000000..93f33118f --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.Development.json @@ -0,0 +1,145 @@ +{ + "AgileConfig": { + "IsEnabled": false, + "env": "DEV", + "appId": "PackageName.CompanyName.ProjectName", + "secret": "1q2w3E*", + "nodes": "http://127.0.0.1:15000", + "name": "PackageName.CompanyName.ProjectName", + "tag": "PackageName.CompanyName.ProjectName" + }, + "Auditing": { + "AllEntitiesSelector": true + }, + "DistributedCache": { + "HideErrors": true, + "KeyPrefix": "LINGYUN.Abp.Application", + "GlobalCacheEntryOptions": { + "SlidingExpiration": "30:00:00", + "AbsoluteExpirationRelativeToNow": "60:00:00" + } + }, + "ConnectionStrings": { + "Default": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "ProjectName": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpSaas": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpFeatureManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpPermissionManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpSettingManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpLocalizationManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpTextTemplating": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456" + }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=15" + } + }, + "OpenTelemetry": { + "IsEnabled": true, + "ZipKin": { + "Endpoint": "http://127.0.0.1:9411/api/v2/spans" + } + }, + "RemoteServices": {}, + "IdentityClients": { + "InternalServiceClient": { + "Authority": "http://127.0.0.1:44385", + "RequireHttps": false, + "GrantType": "client_credentials", + "Scope": "lingyun-abp-application", + "ClientId": "InternalServiceClient", + "ClientSecret": "1q2w3E*" + } + }, + "CAP": { + "EventBus": { + "DefaultGroupName": "ProjectName", + "GroupNamePrefix": "Dev", + "Version": "v1", + "FailedRetryInterval": 300, + "FailedRetryCount": 10 + }, + "MySql": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456" + }, + "SqlServer": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456" + }, + "Sqlite": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Data Source=./cap.db" + }, + "Oracle": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Data Source=ProjectName;Integrated Security=yes;" + }, + "PostgreSql": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Host=localhost;Port=5432;Database=ProjectName;User ID=root;Password=123456;" + }, + "RabbitMQ": { + "HostName": "127.0.0.1", + "Port": 5672, + "UserName": "admin", + "Password": "123456", + "ExchangeName": "LINGYUN.Abp.Application", + "VirtualHost": "/" + } + }, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=10", + "InstanceName": "LINGYUN.Abp.Application" + }, + "AuthServer": { + "Authority": "http://127.0.0.1:44385/", + "ApiName": "lingyun-abp-application", + "SwaggerClientId": "InternalServiceClient", + "SwaggerClientSecret": "1q2w3E*" + }, + "Logging": { + "Serilog": { + "Elasticsearch": { + "IndexFormat": "abp.dev.logging-{0:yyyy.MM.dd}" + } + } + }, + "AuditLogging": { + "Elasticsearch": { + "IndexPrefix": "abp.dev.auditing" + } + }, + "Elasticsearch": { + "NodeUris": "http://127.0.0.1:9200" + }, + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "DotNetCore": "Debug" + } + }, + "WriteTo": [ + { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Debug", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "Elasticsearch", + "Args": { + "nodeUris": "http://127.0.0.1:9200", + "indexFormat": "abp.dev.logging-{0:yyyy.MM.dd}", + "autoRegisterTemplate": true, + "autoRegisterTemplateVersion": "ESv7" + } + } + ] + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.json b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.json new file mode 100644 index 000000000..d3d63c269 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.DbMigrator/appsettings.json @@ -0,0 +1,80 @@ +{ + "StringEncryption": { + "DefaultPassPhrase": "s46c5q55nxpeS8Ra", + "InitVectorBytes": "s83ng0abvd02js84", + "DefaultSalt": "sf&5)s3#" + }, + "AllowedHosts": "*", + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft.EntityFrameworkCore": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId", "WithEnvironmentName", "WithMachineName", "WithApplicationName", "WithUniqueId" ], + "WriteTo": [ + { + "Name": "Console", + "Args": { + "initialMinimumLevel": "Verbose", + "standardErrorFromLevel": "Verbose", + "restrictedToMinimumLevel": "Verbose", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Debug-.log", + "restrictedToMinimumLevel": "Debug", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Info-.log", + "restrictedToMinimumLevel": "Information", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Warn-.log", + "restrictedToMinimumLevel": "Warning", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Error-.log", + "restrictedToMinimumLevel": "Error", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Fatal-.log", + "restrictedToMinimumLevel": "Fatal", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Controllers/HomeController.cs b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Controllers/HomeController.cs new file mode 100644 index 000000000..f38f64d84 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Controllers/HomeController.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; + +namespace PackageName.CompanyName.ProjectName.Controllers; + +public class HomeController : AbpController +{ + public IActionResult Index() + { + return Redirect("/swagger/index.html"); + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Dockerfile b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Dockerfile new file mode 100644 index 000000000..dfd0d25d1 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Dockerfile @@ -0,0 +1,20 @@ +FROM mcr.microsoft.com/dotnet/aspnet:7.0 +LABEL maintainer="colin.in@foxmail.com" +WORKDIR /app + +COPY . /app + +## 设置上海时区.(Set your own time zone.) +#ENV TZ=Asia/Shanghai +#RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo '$TZ' > /etc/timezone + +## 解决连接SqlServer TLS版本过高问题.(The version of connection SqlServer TLS is too high.) +## 如果数据提供者是SqlServer,需要手动取消注释.(If the data provider is SqlServer, you need to manually uncomment it.) +##RUN sed -i 's/TLSv1.2/TLSv1.0/g' /etc/ssl/openssl.cnf +##RUN sed -i 's/TLSv1.2/TLSv1.0/g' /usr/lib/ssl/openssl.cnf + +EXPOSE 80/tcp +VOLUME [ "./app/Logs" ] +VOLUME [ "./app/Modules" ] + +ENTRYPOINT ["dotnet", "PackageName.CompanyName.ProjectName.HttpApi.Host.dll"] diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs new file mode 100644 index 000000000..1c6f1aae7 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/EventBus/Handlers/TenantSynchronizer.cs @@ -0,0 +1,81 @@ +using PackageName.CompanyName.ProjectName.EntityFrameworkCore; +using LINGYUN.Abp.Data.DbMigrator; +using LINGYUN.Abp.MultiTenancy; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.EventBus.Distributed; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Uow; + +namespace PackageName.CompanyName.ProjectName.EventBus.Handlers; + +public class TenantSynchronizer : + IDistributedEventHandler, + ITransientDependency +{ + protected IDataSeeder DataSeeder { get; } + protected ICurrentTenant CurrentTenant { get; } + protected IDbSchemaMigrator DbSchemaMigrator { get; } + protected IUnitOfWorkManager UnitOfWorkManager { get; } + + protected ILogger Logger { get; } + + public TenantSynchronizer( + IDataSeeder dataSeeder, + ICurrentTenant currentTenant, + IDbSchemaMigrator dbSchemaMigrator, + IUnitOfWorkManager unitOfWorkManager, + ILogger logger) + { + DataSeeder = dataSeeder; + CurrentTenant = currentTenant; + DbSchemaMigrator = dbSchemaMigrator; + UnitOfWorkManager = unitOfWorkManager; + + Logger = logger; + } + + /// + /// 租户创建之后需要预置种子数据 + /// + /// + /// + public virtual async Task HandleEventAsync(CreateEventData eventData) + { + using (var unitOfWork = UnitOfWorkManager.Begin()) + { + using (CurrentTenant.Change(eventData.Id, eventData.Name)) + { + Logger.LogInformation("Migrating the new tenant database with PackageName.CompanyName.ProjectName..."); + // 迁移租户数据 + await DbSchemaMigrator.MigrateAsync( + (connectionString, builder) => + { +#if MySQL + builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); +#elif SqlServer + builder.UseSqlServer(connectionString); +#elif Sqlite + builder.UseSqlite(connectionString); +#elif Oracle + builder.UseOracle(connectionString); +#elif OracleDevart + builder.UseOracle(connectionString); +#elif PostgreSql + builder.UseNpgsql(connectionString); +#endif + + return new ProjectNameDbContext(builder.Options); + }); + Logger.LogInformation("Migrated the new tenant database with PackageName.CompanyName.ProjectName..."); + + await DataSeeder.SeedAsync(new DataSeedContext(eventData.Id)); + + await unitOfWork.SaveChangesAsync(); + } + } + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj new file mode 100644 index 000000000..df2c575be --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/PackageName.CompanyName.ProjectName.HttpApi.Host.csproj @@ -0,0 +1,74 @@ + + + + net7.0 + PackageName.CompanyName.ProjectName + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Program.cs b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Program.cs new file mode 100644 index 000000000..0fbaf6dfa --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Program.cs @@ -0,0 +1,61 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.IO; +using Volo.Abp.Modularity.PlugIns; + +namespace PackageName.CompanyName.ProjectName; + +public class Program +{ + public async static Task Main(string[] args) + { + try + { + Log.Information("Starting web host."); + + var builder = WebApplication.CreateBuilder(args); + builder.Host.AddAppSettingsSecretsJson() + .UseAutofac() + .ConfigureAppConfiguration((context, config) => + { + var configuration = config.Build(); + var agileConfigEnabled = configuration["AgileConfig:IsEnabled"]; + if (agileConfigEnabled.IsNullOrEmpty() || bool.Parse(agileConfigEnabled)) + { + config.AddAgileConfig(new AgileConfig.Client.ConfigClient(configuration)); + } + }) + .UseSerilog((context, provider, config) => + { + config.ReadFrom.Configuration(context.Configuration); + }); + await builder.AddApplicationAsync(options => + { + // 搜索 Modules 目录下所有文件作为插件 + // 取消显示引用所有其他项目的模块,改为通过插件的形式引用 + var pluginFolder = Path.Combine( + Directory.GetCurrentDirectory(), "Modules"); + DirectoryHelper.CreateIfNotExists(pluginFolder); + options.PlugInSources.AddFolder( + pluginFolder, + SearchOption.AllDirectories); + }); + var app = builder.Build(); + await app.InitializeApplicationAsync(); + await app.RunAsync(); + return 0; + } + finally + { + Log.CloseAndFlush(); + } + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.Configure.cs b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.Configure.cs new file mode 100644 index 000000000..a13c42307 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.Configure.cs @@ -0,0 +1,361 @@ +using DotNetCore.CAP; +using LINGYUN.Abp.Dapr.Client.ClientProxying; +using LINGYUN.Abp.Dapr.Client.DynamicProxying; +using LINGYUN.Abp.ExceptionHandling; +using LINGYUN.Abp.ExceptionHandling.Emailing; +using LINGYUN.Abp.Localization.CultureMap; +using LINGYUN.Abp.Localization.Persistence; +using LINGYUN.Abp.Serilog.Enrichers.Application; +using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using LINGYUN.Abp.Wrapper; +using Medallion.Threading; +using Medallion.Threading.Redis; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Caching.StackExchangeRedis; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using OpenTelemetry.Resources; +using OpenTelemetry.Trace; +using PackageName.CompanyName.ProjectName.Localization; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.Text.Encodings.Web; +using System.Text.Unicode; +using Volo.Abp; +using Volo.Abp.Auditing; +using Volo.Abp.Caching; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.GlobalFeatures; +using Volo.Abp.Http.Client; +using Volo.Abp.Json; +using Volo.Abp.Json.SystemTextJson; +using Volo.Abp.Localization; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; +using Volo.Abp.VirtualFileSystem; +using static IdentityModel.ClaimComparer; + +namespace PackageName.CompanyName.ProjectName; + +public partial class ProjectNameHttpApiHostModule +{ + protected const string ApplicationName = "ProjectName"; + private static readonly OneTimeRunner OneTimeRunner = new(); + + private void PreConfigureFeature() + { + OneTimeRunner.Run(() => + { + GlobalFeatureManager.Instance.Modules.Editions().EnableAll(); + }); + } + + private void PreConfigureApp() + { + AbpSerilogEnrichersConsts.ApplicationName = ApplicationName; + + PreConfigure(options => + { + // 以开放端口区别 + options.SnowflakeIdOptions.WorkerId = 5; + options.SnowflakeIdOptions.WorkerIdBits = 5; + options.SnowflakeIdOptions.DatacenterId = 1; + }); + } + + private void PreConfigureCAP(IConfiguration configuration) + { + PreConfigure(options => + { + options +#if MySQL + .UseMySql(sqlOptions => + { + configuration.GetSection("CAP:MySql").Bind(sqlOptions); + }) +#elif SqlServer + .UseSqlServer(sqlOptions => + { + configuration.GetSection("CAP:SqlServer").Bind(sqlOptions); + }) +#elif Sqlite + .UseSqlite(sqlOptions => + { + configuration.GetSection("CAP:Sqlite").Bind(sqlOptions); + }) +#elif Oracle || OracleDevart + .UseOracle(sqlOptions => + { + configuration.GetSection("CAP:Oracle").Bind(sqlOptions); + }) +#elif PostgreSql + .UsePostgreSql(sqlOptions => + { + configuration.GetSection("CAP:PostgreSql").Bind(sqlOptions); + }) +#endif + .UseRabbitMQ(rabbitMQOptions => + { + configuration.GetSection("CAP:RabbitMQ").Bind(rabbitMQOptions); + }) + .UseDashboard(); + }); + } + + private void ConfigureJsonSerializer() + { + // 解决某些不支持类型的序列化 + Configure(options => + { + options.OutputDateTimeFormat = "yyyy-MM-dd HH:mm:ss"; + options.InputDateTimeFormats.AddIfNotContains("yyyy-MM-dd HH:mm:ss"); + options.InputDateTimeFormats.AddIfNotContains("yyyy-MM-ddTHH:mm:ss"); + }); + // 中文序列化的编码问题 + Configure(options => + { + options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); + }); + } + + private void ConfigureDistributedLock(IServiceCollection services, IConfiguration configuration) + { + var distributedLockEnabled = configuration["Redis:IsEnabled"]; + if (distributedLockEnabled.IsNullOrEmpty() || bool.Parse(distributedLockEnabled)) + { + var redis = ConnectionMultiplexer.Connect(configuration["DistributedLock:Redis:Configuration"]); + services.AddSingleton(_ => new RedisDistributedSynchronizationProvider(redis.GetDatabase())); + } + } + + private void ConfigureOpenTelemetry(IServiceCollection services, IConfiguration configuration) + { + var openTelemetryEnabled = configuration["OpenTelemetry:IsEnabled"]; + if (openTelemetryEnabled.IsNullOrEmpty() || bool.Parse(openTelemetryEnabled)) + { + services.AddOpenTelemetryTracing(cfg => + { + cfg.AddSource(ApplicationName) + .SetResourceBuilder( + ResourceBuilder.CreateDefault().AddService(ApplicationName)) + .AddHttpClientInstrumentation() + .AddAspNetCoreInstrumentation() + .AddEntityFrameworkCoreInstrumentation() + .AddCapInstrumentation() + .AddZipkinExporter(zipKinOptions => + { + var endpoint = configuration["OpenTelemetry:ZipKin:Endpoint"]; + if (!endpoint.IsNullOrWhiteSpace()) + { + zipKinOptions.Endpoint = new Uri(configuration["OpenTelemetry:ZipKin:Endpoint"]); + } + }); + }); + } + } + + private void ConfigureExceptionHandling() + { + // 自定义需要处理的异常 + Configure(options => + { + // 加入需要处理的异常类型 + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + options.Handlers.Add(); + }); + // 自定义需要发送邮件通知的异常类型 + Configure(options => + { + // 是否发送堆栈信息 + options.SendStackTrace = true; + // 未指定异常接收者的默认接收邮件 + // 指定自己的邮件地址 + }); + } + + private void ConfigureAuditing(IConfiguration configuration) + { + Configure(options => + { + options.ApplicationName = ApplicationName; + // 是否启用实体变更记录 + var allEntitiesSelectorIsEnabled = configuration["Auditing:AllEntitiesSelector"]; + if (allEntitiesSelectorIsEnabled.IsNullOrWhiteSpace() || + (bool.TryParse(allEntitiesSelectorIsEnabled, out var enabled) && enabled)) + { + options.EntityHistorySelectors.AddAllEntities(); + } + }); + } + + private void ConfigureCaching(IConfiguration configuration) + { + Configure(options => + { + configuration.GetSection("DistributedCache").Bind(options); + }); + + Configure(options => + { + var redisConfig = ConfigurationOptions.Parse(options.Configuration); + options.ConfigurationOptions = redisConfig; + options.InstanceName = configuration["Redis:InstanceName"]; + }); + } + + private void ConfigureVirtualFileSystem() + { + Configure(options => + { + options.FileSets.AddEmbedded("PackageName.CompanyName.ProjectName"); + }); + } + + private void ConfigureMultiTenancy(IConfiguration configuration) + { + // 多租户 + Configure(options => + { + options.IsEnabled = true; + }); + + var tenantResolveCfg = configuration.GetSection("App:Domains"); + if (tenantResolveCfg.Exists()) + { + Configure(options => + { + var domains = tenantResolveCfg.Get(); + foreach (var domain in domains) + { + options.AddDomainTenantResolver(domain); + } + }); + } + } + + private void ConfigureSwagger(IServiceCollection services) + { + // Swagger + services.AddSwaggerGen( + options => + { + options.SwaggerDoc("v1", new OpenApiInfo { Title = "ProjectName API", Version = "v1" }); + options.DocInclusionPredicate((docName, description) => true); + options.CustomSchemaIds(type => type.FullName); + options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme + { + Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", + Name = "Authorization", + In = ParameterLocation.Header, + Scheme = "bearer", + Type = SecuritySchemeType.Http, + BearerFormat = "JWT" + }); + options.AddSecurityRequirement(new OpenApiSecurityRequirement + { + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } + }, + new string[] { } + } + }); + options.OperationFilter(); + }); + } + + private void ConfigureLocalization() + { + // 支持本地化语言类型 + Configure(options => + { + options.Languages.Add(new LanguageInfo("en", "en", "English")); + options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); + }); + + Configure(options => + { + // 持久化本地化资源 + options.SaveStaticLocalizationsToPersistence = true; + options.AddPersistenceResource(); + }); + + Configure(options => + { + var zhHansCultureMapInfo = new CultureMapInfo + { + TargetCulture = "zh-Hans", + SourceCultures = new string[] { "zh", "zh_CN", "zh-CN" } + }; + + options.CulturesMaps.Add(zhHansCultureMapInfo); + options.UiCulturesMaps.Add(zhHansCultureMapInfo); + }); + } + + private void ConfigureSecurity(IServiceCollection services, IConfiguration configuration, bool isDevelopment = false) + { + services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.Authority = configuration["AuthServer:Authority"]; + options.Audience = configuration["AuthServer:ApiName"]; + options.RequireHttpsMetadata = Convert.ToBoolean(configuration["AuthServer:RequireHttpsMetadata"]); + }); + + if (!isDevelopment) + { + var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); + services + .AddDataProtection() + .SetApplicationName("LINGYUN.Abp.Application") + .PersistKeysToStackExchangeRedis(redis, "LINGYUN.Abp.Application:DataProtection:Protection-Keys"); + } + } + + private void ConfigureWrapper() + { + Configure(options => + { + // 取消注释包装结果 + // options.IsEnabled = true; + }); + + Configure(options => + { + // http服务间调用发送不需要包装结果的请求头 + options.ProxyClientBuildActions.Add( + (_, builder) => + { + builder.ConfigureHttpClient((provider, client) => + { + var wrapperOptions = provider.GetRequiredService>(); + var wrapperHeader = wrapperOptions.Value.IsEnabled + ? AbpHttpWrapConsts.AbpWrapResult + : AbpHttpWrapConsts.AbpDontWrapResult; + + client.DefaultRequestHeaders.TryAddWithoutValidation(wrapperHeader, "true"); + }); + }); + }); + + Configure(options => + { + // dapr服务间调用发送不需要包装结果的请求头 + options.ProxyRequestActions.Add( + (appId, httpRequestMessage) => + { + httpRequestMessage.Headers.TryAddWithoutValidation(AbpHttpWrapConsts.AbpDontWrapResult, "true"); + }); + }); + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs new file mode 100644 index 000000000..65dde60c7 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/ProjectNameHttpApiHostModule.cs @@ -0,0 +1,128 @@ +using LINGYUN.Abp.AspNetCore.Mvc.Wrapper; +using LINGYUN.Abp.AuditLogging.Elasticsearch; +using LINGYUN.Abp.EventBus.CAP; +using LINGYUN.Abp.ExceptionHandling.Emailing; +using LINGYUN.Abp.LocalizationManagement.EntityFrameworkCore; +using LINGYUN.Abp.TextTemplating.EntityFrameworkCore; +using LINGYUN.Abp.Saas.EntityFrameworkCore; +using LINGYUN.Abp.Serilog.Enrichers.Application; +using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using PackageName.CompanyName.ProjectName.EntityFrameworkCore; +using PackageName.CompanyName.ProjectName.SettingManagement; +using Volo.Abp; +#if IdentityServer4 +using Volo.Abp.AspNetCore.Authentication.JwtBearer; +#elif OpenIddict +using Volo.Abp.OpenIddict; +#endif +using Volo.Abp.AspNetCore.MultiTenancy; +using Volo.Abp.AspNetCore.Serilog; +using Volo.Abp.Autofac; +using Volo.Abp.Caching.StackExchangeRedis; +using Volo.Abp.DistributedLocking; +using Volo.Abp.FeatureManagement.EntityFrameworkCore; +using Volo.Abp.Http.Client.IdentityModel.Web; +using Volo.Abp.Modularity; +using Volo.Abp.PermissionManagement.EntityFrameworkCore; +using Volo.Abp.SettingManagement.EntityFrameworkCore; +using Volo.Abp.Swashbuckle; + +namespace PackageName.CompanyName.ProjectName; + +[DependsOn( + typeof(AbpSerilogEnrichersApplicationModule), + typeof(AbpSerilogEnrichersUniqueIdModule), + typeof(AbpAuditLoggingElasticsearchModule), + typeof(AbpAspNetCoreSerilogModule), + typeof(ProjectNameApplicationModule), + typeof(ProjectNameHttpApiModule), + typeof(ProjectNameEntityFrameworkCoreModule), + typeof(ProjectNameSettingManagementModule), + typeof(AbpEmailingExceptionHandlingModule), + typeof(AbpCAPEventBusModule), + typeof(AbpHttpClientIdentityModelWebModule), + typeof(AbpAspNetCoreMultiTenancyModule), + typeof(AbpSaasEntityFrameworkCoreModule), + typeof(AbpFeatureManagementEntityFrameworkCoreModule), + typeof(AbpPermissionManagementEntityFrameworkCoreModule), + typeof(AbpSettingManagementEntityFrameworkCoreModule), + typeof(AbpLocalizationManagementEntityFrameworkCoreModule), + typeof(AbpTextTemplatingEntityFrameworkCoreModule), +#if IdentityServer4 + typeof(AbpAspNetCoreAuthenticationJwtBearerModule), +#elif OpenIddict + typeof(AbpOpenIddictAspNetCoreModule), +#endif + typeof(AbpCachingStackExchangeRedisModule), + typeof(AbpDistributedLockingModule), + typeof(AbpAspNetCoreMvcWrapperModule), + typeof(AbpSwashbuckleModule), + typeof(AbpAutofacModule) + )] +public partial class ProjectNameHttpApiHostModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + + PreConfigureApp(); + PreConfigureFeature(); + PreConfigureCAP(configuration); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var hostingEnvironment = context.Services.GetHostingEnvironment(); + var configuration = context.Services.GetConfiguration(); + + ConfigureWrapper(); + ConfigureLocalization(); + ConfigureJsonSerializer(); + ConfigureExceptionHandling(); + ConfigureVirtualFileSystem(); + ConfigureCaching(configuration); + ConfigureAuditing(configuration); + ConfigureMultiTenancy(configuration); + ConfigureSwagger(context.Services); + ConfigureOpenTelemetry(context.Services, configuration); + ConfigureDistributedLock(context.Services, configuration); + ConfigureSecurity(context.Services, configuration, hostingEnvironment.IsDevelopment()); + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + var env = context.GetEnvironment(); + + app.UseMapRequestLocalization(); + app.UseCorrelationId(); + app.UseStaticFiles(); + app.UseRouting(); + app.UseCors(); + app.UseAuthentication(); +#if IdentityServer4 + app.UseJwtTokenMiddleware(); +#elif OpenIddict + app.UseAbpOpenIddictValidation(); +#endif + app.UseMultiTenancy(); + app.UseAuthorization(); + app.UseSwagger(); + app.UseAbpSwaggerUI(options => + { + options.SwaggerEndpoint("/swagger/v1/swagger.json", "Support ProjectName API"); + + var configuration = context.GetConfiguration(); + options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); + options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]); + options.OAuthScopes("ProjectName"); + }); + app.UseAuditing(); + app.UseAbpSerilogEnrichers(); + app.UseConfiguredEndpoints(); + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Properties/launchSettings.json b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Properties/launchSettings.json new file mode 100644 index 000000000..bfc8f50b6 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/Properties/launchSettings.json @@ -0,0 +1,28 @@ +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:20890", + "sslPort": 0 + } + }, + "profiles": { + "PackageName.CompanyName.ProjectName.HttpApi.Host": { + "commandName": "Project", + "launchBrowser": false, + "dotnetRunMessages": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://127.0.0.1:5000" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": false, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} \ No newline at end of file diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/TenantHeaderParamter.cs b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/TenantHeaderParamter.cs new file mode 100644 index 000000000..265c287de --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/TenantHeaderParamter.cs @@ -0,0 +1,31 @@ +using Microsoft.Extensions.Options; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using System.Collections.Generic; +using Volo.Abp.MultiTenancy; + +namespace PackageName.CompanyName.ProjectName; + +public class TenantHeaderParamter : IOperationFilter +{ + private readonly AbpMultiTenancyOptions _options; + public TenantHeaderParamter( + IOptions options) + { + _options = options.Value; + } + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + if (_options.IsEnabled) + { + operation.Parameters = operation.Parameters ?? new List(); + operation.Parameters.Add(new OpenApiParameter + { + Name = TenantResolverConsts.DefaultTenantKey, + In = ParameterLocation.Header, + Description = "Tenant Id/Name", + Required = false + }); + } + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.Development.json b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.Development.json new file mode 100644 index 000000000..c6e784dad --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.Development.json @@ -0,0 +1,146 @@ +{ + "AgileConfig": { + "IsEnabled": false, + "env": "DEV", + "appId": "PackageName.CompanyName.ProjectName", + "secret": "1q2w3E*", + "nodes": "http://127.0.0.1:15000", + "name": "PackageName.CompanyName.ProjectName", + "tag": "PackageName.CompanyName.ProjectName" + }, + "Auditing": { + "AllEntitiesSelector": true + }, + "DistributedCache": { + "HideErrors": true, + "KeyPrefix": "LINGYUN.Abp.Application", + "GlobalCacheEntryOptions": { + "SlidingExpiration": "30:00:00", + "AbsoluteExpirationRelativeToNow": "60:00:00" + } + }, + "ConnectionStrings": { + "Default": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "ProjectName": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpSaas": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpFeatureManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpPermissionManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpSettingManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpLocalizationManagement": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456", + "AbpTextTemplating": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456" + }, + "DistributedLock": { + "IsEnabled": true, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=15" + } + }, + "OpenTelemetry": { + "IsEnabled": true, + "ZipKin": { + "Endpoint": "http://127.0.0.1:9411/api/v2/spans" + } + }, + "RemoteServices": {}, + "IdentityClients": { + "InternalServiceClient": { + "Authority": "http://127.0.0.1:44385", + "RequireHttps": false, + "GrantType": "client_credentials", + "Scope": "lingyun-abp-application", + "ClientId": "InternalServiceClient", + "ClientSecret": "1q2w3E*" + } + }, + "CAP": { + "EventBus": { + "DefaultGroupName": "ProjectName", + "GroupNamePrefix": "Dev", + "Version": "v1", + "FailedRetryInterval": 300, + "FailedRetryCount": 10 + }, + "MySql": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456" + }, + "SqlServer": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Server=127.0.0.1;Database=ProjectName;User Id=root;Password=123456" + }, + "Sqlite": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Data Source=./cap.db" + }, + "Oracle": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Data Source=ProjectName;Integrated Security=yes;" + }, + "PostgreSql": { + "TableNamePrefix": "ProjectName_cap", + "ConnectionString": "Host=localhost;Port=5432;Database=ProjectName;User ID=root;Password=123456;" + }, + "RabbitMQ": { + "HostName": "127.0.0.1", + "Port": 5672, + "UserName": "admin", + "Password": "123456", + "ExchangeName": "LINGYUN.Abp.Application", + "VirtualHost": "/" + } + }, + "Redis": { + "Configuration": "127.0.0.1,defaultDatabase=10", + "InstanceName": "LINGYUN.Abp.Application" + }, + "AuthServer": { + "Authority": "http://127.0.0.1:44385/", + "ApiName": "lingyun-abp-application", + "RequireHttpsMetadata": false, + "SwaggerClientId": "InternalServiceClient", + "SwaggerClientSecret": "1q2w3E*" + }, + "Logging": { + "Serilog": { + "Elasticsearch": { + "IndexFormat": "abp.dev.logging-{0:yyyy.MM.dd}" + } + } + }, + "AuditLogging": { + "Elasticsearch": { + "IndexPrefix": "abp.dev.auditing" + } + }, + "Elasticsearch": { + "NodeUris": "http://127.0.0.1:9200" + }, + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "System": "Warning", + "Microsoft": "Warning", + "DotNetCore": "Debug" + } + }, + "WriteTo": [ + { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Debug", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "Elasticsearch", + "Args": { + "nodeUris": "http://127.0.0.1:9200", + "indexFormat": "abp.dev.logging-{0:yyyy.MM.dd}", + "autoRegisterTemplate": true, + "autoRegisterTemplateVersion": "ESv7" + } + } + ] + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json new file mode 100644 index 000000000..d3d63c269 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/appsettings.json @@ -0,0 +1,80 @@ +{ + "StringEncryption": { + "DefaultPassPhrase": "s46c5q55nxpeS8Ra", + "InitVectorBytes": "s83ng0abvd02js84", + "DefaultSalt": "sf&5)s3#" + }, + "AllowedHosts": "*", + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft.EntityFrameworkCore": "Debug", + "System": "Information", + "Microsoft": "Information" + } + }, + "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId", "WithEnvironmentName", "WithMachineName", "WithApplicationName", "WithUniqueId" ], + "WriteTo": [ + { + "Name": "Console", + "Args": { + "initialMinimumLevel": "Verbose", + "standardErrorFromLevel": "Verbose", + "restrictedToMinimumLevel": "Verbose", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Debug-.log", + "restrictedToMinimumLevel": "Debug", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Info-.log", + "restrictedToMinimumLevel": "Information", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Warn-.log", + "restrictedToMinimumLevel": "Warning", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Error-.log", + "restrictedToMinimumLevel": "Error", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Fatal-.log", + "restrictedToMinimumLevel": "Fatal", + "rollingInterval": "Day", + "fileSizeLimitBytes": 5242880, + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] + } +} diff --git a/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/dapr.sh b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/dapr.sh new file mode 100644 index 000000000..01a8eb036 --- /dev/null +++ b/aspnet-core/templates/content/host/PackageName.CompanyName.ProjectName.HttpApi.Host/dapr.sh @@ -0,0 +1 @@ +dapr run --app-id ProjectName --app-port 5000 -H 3500 -- dotnet run --no-build \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/FodyWeavers.xml b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/FodyWeavers.xsd b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName.CompanyName.ProjectName.Application.Contracts.csproj b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName.CompanyName.ProjectName.Application.Contracts.csproj new file mode 100644 index 000000000..4eb9907a3 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName.CompanyName.ProjectName.Application.Contracts.csproj @@ -0,0 +1,22 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Authorization/ProjectNamePermissionDefinitionProvider.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Authorization/ProjectNamePermissionDefinitionProvider.cs new file mode 100644 index 000000000..487837400 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Authorization/ProjectNamePermissionDefinitionProvider.cs @@ -0,0 +1,22 @@ +using PackageName.CompanyName.ProjectName.Localization; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Localization; + +namespace PackageName.CompanyName.ProjectName.Authorization; + +public class ProjectNamePermissionDefinitionProvider : PermissionDefinitionProvider +{ + public override void Define(IPermissionDefinitionContext context) + { + var group = context.AddGroup(ProjectNamePermissions.GroupName, L("Permission:ProjectName")); + + group.AddPermission( + ProjectNamePermissions.ManageSettings, + L("Permission:ManageSettings")); + } + + private static LocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Authorization/ProjectNamePermissions.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Authorization/ProjectNamePermissions.cs new file mode 100644 index 000000000..257d11988 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Authorization/ProjectNamePermissions.cs @@ -0,0 +1,8 @@ +namespace PackageName.CompanyName.ProjectName.Authorization; + +public static class ProjectNamePermissions +{ + public const string GroupName = "ProjectName"; + + public const string ManageSettings = GroupName + ".ManageSettings"; +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Features/ProjectNameFeatureDefinitionProvider.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Features/ProjectNameFeatureDefinitionProvider.cs new file mode 100644 index 000000000..0dd18f176 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Features/ProjectNameFeatureDefinitionProvider.cs @@ -0,0 +1,18 @@ +using PackageName.CompanyName.ProjectName.Localization; +using Volo.Abp.Features; +using Volo.Abp.Localization; + +namespace PackageName.CompanyName.ProjectName.Features; + +public class ProjectNameFeatureDefinitionProvider : FeatureDefinitionProvider +{ + public override void Define(IFeatureDefinitionContext context) + { + var group = context.AddGroup(ProjectNameFeatureNames.GroupName, L("Features:ProjectName")); + } + + private static ILocalizableString L(string name) + { + return LocalizableString.Create(name); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Features/ProjectNameFeatureNames.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Features/ProjectNameFeatureNames.cs new file mode 100644 index 000000000..4af07a047 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/Features/ProjectNameFeatureNames.cs @@ -0,0 +1,6 @@ +namespace PackageName.CompanyName.ProjectName.Features; + +public static class ProjectNameFeatureNames +{ + public const string GroupName = "ProjectName"; +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/IProjectNameDynamicQueryableAppService.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/IProjectNameDynamicQueryableAppService.cs new file mode 100644 index 000000000..6cb9ead42 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/IProjectNameDynamicQueryableAppService.cs @@ -0,0 +1,10 @@ +using LINGYUN.Abp.Dynamic.Queryable; + +namespace PackageName.CompanyName.ProjectName; +/// +/// 提供动态查询接口定义 +/// +/// 实体dto类型 +public interface IProjectNameDynamicQueryableAppService : IDynamicQueryableAppService +{ +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/ProjectNameApplicationContractsModule.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/ProjectNameApplicationContractsModule.cs new file mode 100644 index 000000000..9899a0c97 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/ProjectNameApplicationContractsModule.cs @@ -0,0 +1,17 @@ +using LINGYUN.Abp.Dynamic.Queryable; +using Volo.Abp.Application; +using Volo.Abp.Authorization; +using Volo.Abp.Features; +using Volo.Abp.Modularity; + +namespace PackageName.CompanyName.ProjectName; + +[DependsOn( + typeof(AbpFeaturesModule), + typeof(AbpAuthorizationModule), + typeof(AbpDddApplicationContractsModule), + typeof(AbpDynamicQueryableApplicationContractsModule), + typeof(ProjectNameDomainSharedModule))] +public class ProjectNameApplicationContractsModule : AbpModule +{ +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/ProjectNameRemoteServiceConsts.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/ProjectNameRemoteServiceConsts.cs new file mode 100644 index 000000000..ef949b273 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application.Contracts/PackageName/CompanyName/ProjectName/ProjectNameRemoteServiceConsts.cs @@ -0,0 +1,7 @@ +namespace PackageName.CompanyName.ProjectName; + +public static class ProjectNameRemoteServiceConsts +{ + public const string RemoteServiceName = "ProjectName"; + public const string ModuleName = "ProjectName"; +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/FodyWeavers.xml b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/FodyWeavers.xsd b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName.CompanyName.ProjectName.Application.csproj b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName.CompanyName.ProjectName.Application.csproj new file mode 100644 index 000000000..c301dd4fb --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName.CompanyName.ProjectName.Application.csproj @@ -0,0 +1,21 @@ + + + + + + + netstandard2.1 + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameAppServiceBase.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameAppServiceBase.cs new file mode 100644 index 000000000..458c4dd29 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameAppServiceBase.cs @@ -0,0 +1,13 @@ +using PackageName.CompanyName.ProjectName.Localization; +using Volo.Abp.Application.Services; + +namespace PackageName.CompanyName.ProjectName; + +public abstract class ProjectNameAppServiceBase : ApplicationService +{ + protected ProjectNameAppServiceBase() + { + LocalizationResource = typeof(ProjectNameResource); + ObjectMapperContext = typeof(ProjectNameApplicationModule); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMapperProfile.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMapperProfile.cs new file mode 100644 index 000000000..b16e2bc1b --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationMapperProfile.cs @@ -0,0 +1,10 @@ +using AutoMapper; + +namespace PackageName.CompanyName.ProjectName; + +public class ProjectNameApplicationMapperProfile : Profile +{ + public ProjectNameApplicationMapperProfile() + { + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationModule.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationModule.cs new file mode 100644 index 000000000..723aa233e --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameApplicationModule.cs @@ -0,0 +1,27 @@ +using LINGYUN.Abp.Dynamic.Queryable; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Application; +using Volo.Abp.Authorization; +using Volo.Abp.AutoMapper; +using Volo.Abp.Modularity; + +namespace PackageName.CompanyName.ProjectName; + +[DependsOn( + typeof(AbpAuthorizationModule), + typeof(AbpDddApplicationModule), + typeof(ProjectNameDomainModule), + typeof(ProjectNameApplicationContractsModule), + typeof(AbpDynamicQueryableApplicationModule))] +public class ProjectNameApplicationModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddProfile(validate: true); + }); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameDynamicQueryableAppServiceBase.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameDynamicQueryableAppServiceBase.cs new file mode 100644 index 000000000..36e98d204 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Application/PackageName/CompanyName/ProjectName/ProjectNameDynamicQueryableAppServiceBase.cs @@ -0,0 +1,19 @@ +using LINGYUN.Abp.Dynamic.Queryable; +using PackageName.CompanyName.ProjectName.Localization; + +namespace PackageName.CompanyName.ProjectName; +/// +/// 提供动态查询接口实现 +/// +/// 实体类型 +/// 实体dto类型 +public abstract class ProjectNameDynamicQueryableAppServiceBase : + DynamicQueryableAppService, + IProjectNameDynamicQueryableAppService +{ + protected ProjectNameDynamicQueryableAppServiceBase() + { + LocalizationResource = typeof(ProjectNameResource); + ObjectMapperContext = typeof(ProjectNameApplicationModule); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/FodyWeavers.xml b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/FodyWeavers.xsd b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/PackageName.CompanyName.ProjectName.Dapr.Client.csproj b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/PackageName.CompanyName.ProjectName.Dapr.Client.csproj new file mode 100644 index 000000000..fc977bba6 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/PackageName.CompanyName.ProjectName.Dapr.Client.csproj @@ -0,0 +1,19 @@ + + + + + + + net7.0 + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/PackageName/CompanyName/ProjectName/ProjectNameDaprClientModule.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/PackageName/CompanyName/ProjectName/ProjectNameDaprClientModule.cs new file mode 100644 index 000000000..115cce260 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Dapr.Client/PackageName/CompanyName/ProjectName/ProjectNameDaprClientModule.cs @@ -0,0 +1,18 @@ +using LINGYUN.Abp.Dapr.Client; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Modularity; + +namespace PackageName.CompanyName.ProjectName; + +[DependsOn( + typeof(AbpDaprClientModule), + typeof(ProjectNameApplicationContractsModule))] +public class ProjectNameDaprClientModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddDaprClientProxies( + typeof(ProjectNameApplicationContractsModule).Assembly, + ProjectNameRemoteServiceConsts.RemoteServiceName); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/FodyWeavers.xml b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/FodyWeavers.xsd b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName.CompanyName.ProjectName.Domain.Shared.csproj b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName.CompanyName.ProjectName.Domain.Shared.csproj new file mode 100644 index 000000000..e10b1cfdd --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName.CompanyName.ProjectName.Domain.Shared.csproj @@ -0,0 +1,25 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/Localization/ProjectNameResource.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/Localization/ProjectNameResource.cs new file mode 100644 index 000000000..11db159c1 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/Localization/ProjectNameResource.cs @@ -0,0 +1,8 @@ +using Volo.Abp.Localization; + +namespace PackageName.CompanyName.ProjectName.Localization; + +[LocalizationResourceName("ProjectName")] +public class ProjectNameResource +{ +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/Localization/Resources/en.json b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/Localization/Resources/en.json new file mode 100644 index 000000000..a529d6960 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/Localization/Resources/en.json @@ -0,0 +1,8 @@ +{ + "culture": "en", + "texts": { + "Features:ProjectName": "ProjectName", + "Permission:ProjectName": "ProjectName", + "Permission:ManageSettings": "Manage Settings" + } +} \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/Localization/Resources/zh-Hans.json b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/Localization/Resources/zh-Hans.json new file mode 100644 index 000000000..e2af58de8 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/Localization/Resources/zh-Hans.json @@ -0,0 +1,8 @@ +{ + "culture": "zh-Hans", + "texts": { + "Features:ProjectName": "ProjectName", + "Permission:ProjectName": "ProjectName", + "Permission:ManageSettings": "管理设置" + } +} \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ObjectExtending/ProjectNameModuleExtensionConfiguration.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ObjectExtending/ProjectNameModuleExtensionConfiguration.cs new file mode 100644 index 000000000..6ce706932 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ObjectExtending/ProjectNameModuleExtensionConfiguration.cs @@ -0,0 +1,16 @@ +using System; +using Volo.Abp.ObjectExtending.Modularity; + +namespace PackageName.CompanyName.ProjectName.ObjectExtending; + +public class ProjectNameModuleExtensionConfiguration : ModuleExtensionConfiguration +{ + public ProjectNameModuleExtensionConfiguration ConfigureProjectName( + Action configureAction) + { + return this.ConfigureEntity( + ProjectNameModuleExtensionConsts.EntityNames.Entity, + configureAction + ); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ObjectExtending/ProjectNameModuleExtensionConfigurationDictionaryExtensions.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ObjectExtending/ProjectNameModuleExtensionConfigurationDictionaryExtensions.cs new file mode 100644 index 000000000..d59e7c515 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ObjectExtending/ProjectNameModuleExtensionConfigurationDictionaryExtensions.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Volo.Abp.ObjectExtending.Modularity; + +namespace PackageName.CompanyName.ProjectName.ObjectExtending; + +public static class ProjectNameModuleExtensionConfigurationDictionaryExtensions +{ + public static ModuleExtensionConfigurationDictionary ConfigureProjectName( + this ModuleExtensionConfigurationDictionary modules, + Action configureAction) + { + return modules.ConfigureModule( + ProjectNameModuleExtensionConsts.ModuleName, + configureAction + ); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ObjectExtending/ProjectNameModuleExtensionConsts.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ObjectExtending/ProjectNameModuleExtensionConsts.cs new file mode 100644 index 000000000..dd5e13da8 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ObjectExtending/ProjectNameModuleExtensionConsts.cs @@ -0,0 +1,11 @@ +namespace PackageName.CompanyName.ProjectName.ObjectExtending; + +public static class ProjectNameModuleExtensionConsts +{ + public const string ModuleName = "ProjectName"; + + public static class EntityNames + { + public const string Entity = "Entity"; + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ProjectNameDomainSharedModule.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ProjectNameDomainSharedModule.cs new file mode 100644 index 000000000..7473c7453 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ProjectNameDomainSharedModule.cs @@ -0,0 +1,32 @@ +using PackageName.CompanyName.ProjectName.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Localization.ExceptionHandling; +using Volo.Abp.Modularity; +using Volo.Abp.VirtualFileSystem; + +namespace PackageName.CompanyName.ProjectName; + +[DependsOn( + typeof(AbpLocalizationModule))] +public class ProjectNameDomainSharedModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + + Configure(options => + { + options.Resources + .Add() + .AddVirtualJson("/PackageName/CompanyName/ProjectName/Localization/Resources"); + }); + + Configure(options => + { + options.MapCodeNamespace(ProjectNameErrorCodes.Namespace, typeof(ProjectNameResource)); + }); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ProjectNameErrorCodes.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ProjectNameErrorCodes.cs new file mode 100644 index 000000000..7a652e651 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain.Shared/PackageName/CompanyName/ProjectName/ProjectNameErrorCodes.cs @@ -0,0 +1,6 @@ +namespace PackageName.CompanyName.ProjectName; + +public static class ProjectNameErrorCodes +{ + public const string Namespace = "ProjectName"; +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/FodyWeavers.xml b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/FodyWeavers.xsd b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName.CompanyName.ProjectName.Domain.csproj b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName.CompanyName.ProjectName.Domain.csproj new file mode 100644 index 000000000..2b70ff5aa --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName.CompanyName.ProjectName.Domain.csproj @@ -0,0 +1,21 @@ + + + + + + + netstandard2.1 + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameSpecificationSupport.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameSpecificationSupport.cs new file mode 100644 index 000000000..3e1975700 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/IProjectNameSpecificationSupport.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Specifications; + +namespace PackageName.CompanyName.ProjectName; +/// +/// 实现接口支持规约化查询 +/// +/// 实体类型 +/// 实体主键类型 +public interface IProjectNameSpecificationSupport + where TEntity : class, IEntity +{ + /// + /// 获取过滤后的实体数量 + /// + /// + /// + /// + Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default); + /// + /// 获取过滤后的实体列表 + /// + /// + /// + /// + /// + /// + /// + Task> GetListAsync( + ISpecification specification, + string sorting = nameof(IEntity.Id), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default); +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDbProperties.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDbProperties.cs new file mode 100644 index 000000000..5cd27642b --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDbProperties.cs @@ -0,0 +1,11 @@ +namespace PackageName.CompanyName.ProjectName; + +public static class ProjectNameDbProperties +{ + public static string DbTablePrefix { get; set; } = "ProjectName_"; + + public static string DbSchema { get; set; } = null; + + + public const string ConnectionStringName = "ProjectName"; +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMapperProfile.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMapperProfile.cs new file mode 100644 index 000000000..b2cc42748 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainMapperProfile.cs @@ -0,0 +1,11 @@ +using AutoMapper; + +namespace PackageName.CompanyName.ProjectName; + +public class ProjectNameDomainMapperProfile : Profile +{ + public ProjectNameDomainMapperProfile() + { + + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainModule.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainModule.cs new file mode 100644 index 000000000..83927c1d2 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/ProjectNameDomainModule.cs @@ -0,0 +1,43 @@ +using Microsoft.Extensions.DependencyInjection; +using PackageName.CompanyName.ProjectName.ObjectExtending; +using Volo.Abp.AutoMapper; +using Volo.Abp.Domain.Entities.Events.Distributed; +using Volo.Abp.Modularity; +using Volo.Abp.ObjectExtending.Modularity; +using Volo.Abp.Threading; + +namespace PackageName.CompanyName.ProjectName; + +[DependsOn( + typeof(AbpAutoMapperModule), + typeof(ProjectNameDomainSharedModule))] +public class ProjectNameDomainModule : AbpModule +{ + private static readonly OneTimeRunner OneTimeRunner = new(); + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAutoMapperObjectMapper(); + + Configure(options => + { + options.AddProfile(validate: true); + }); + + Configure(options => + { + }); + } + + public override void PostConfigureServices(ServiceConfigurationContext context) + { + OneTimeRunner.Run(() => + { + // 扩展实体配置 + //ModuleExtensionConfigurationHelper.ApplyEntityConfigurationToEntity( + // ProjectNameModuleExtensionConsts.ModuleName, + // ProjectNameModuleExtensionConsts.EntityNames.Entity, + // typeof(Entity) + //); + }); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/Settings/ProjectNameSettingDefinitionProvider.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/Settings/ProjectNameSettingDefinitionProvider.cs new file mode 100644 index 000000000..64db558bf --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/Settings/ProjectNameSettingDefinitionProvider.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Settings; + +namespace PackageName.CompanyName.ProjectName.Settings +{ + public class ProjectNameSettingDefinitionProvider : SettingDefinitionProvider + { + public override void Define(ISettingDefinitionContext context) + { + } + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/Settings/ProjectNameSettings.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/Settings/ProjectNameSettings.cs new file mode 100644 index 000000000..7561cf8da --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/PackageName/CompanyName/ProjectName/Settings/ProjectNameSettings.cs @@ -0,0 +1,7 @@ +namespace PackageName.CompanyName.ProjectName.Settings +{ + public static class ProjectNameSettings + { + public const string GroupName = "ProjectName"; + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/System/Linq/Expressions/ExpressionFuncExtensions.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/System/Linq/Expressions/ExpressionFuncExtensions.cs new file mode 100644 index 000000000..74e3c828a --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.Domain/System/Linq/Expressions/ExpressionFuncExtensions.cs @@ -0,0 +1,32 @@ +using Volo.Abp.Specifications; + +namespace System.Linq.Expressions; + +internal static class ExpressionFuncExtensions +{ + public static Expression> AndIf( + this Expression> first, + bool condition, + Expression> second) + { + if (condition) + { + return ExpressionFuncExtender.And(first, second); + } + + return first; + } + + public static Expression> OrIf( + this Expression> first, + bool condition, + Expression> second) + { + if (condition) + { + return ExpressionFuncExtender.Or(first, second); + } + + return first; + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/FodyWeavers.xml b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/FodyWeavers.xsd b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName.CompanyName.ProjectName.EntityFrameworkCore.csproj b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName.CompanyName.ProjectName.EntityFrameworkCore.csproj new file mode 100644 index 000000000..f2c877dd1 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName.CompanyName.ProjectName.EntityFrameworkCore.csproj @@ -0,0 +1,31 @@ + + + + + + + net7.0 + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreSpecificationSupportRepository.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreSpecificationSupportRepository.cs new file mode 100644 index 000000000..a8ce44810 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/EfCoreSpecificationSupportRepository.cs @@ -0,0 +1,60 @@ +using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Dynamic.Core; +using System.Threading; +using System.Threading.Tasks; +using Volo.Abp.Domain.Entities; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Specifications; + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; +/// +/// 实现仓储提供规约化查询 +/// +/// 实体类型 +/// 实体主键类型 +public abstract class EfCoreSpecificationSupportRepository : + EfCoreRepository, + IProjectNameSpecificationSupport + where TEntity : class, IEntity +{ + protected EfCoreSpecificationSupportRepository( + IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + } + + public async virtual Task GetCountAsync( + ISpecification specification, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(specification.ToExpression()) + .CountAsync(GetCancellationToken(cancellationToken)); + } + + public async virtual Task> GetListAsync( + ISpecification specification, + string sorting = nameof(IEntity.Id), + int maxResultCount = 10, + int skipCount = 0, + CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .Where(specification.ToExpression()) + .OrderBy(GetSortingOrDefault(sorting)) + .PageBy(skipCount, maxResultCount) + .ToListAsync(GetCancellationToken(cancellationToken)); + } + + protected virtual string GetSortingOrDefault(string sorting = nameof(IEntity.Id)) + { + if (sorting.IsNullOrWhiteSpace()) + { + return nameof(IEntity.Id); + } + return sorting; + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/IProjectNameDbContext.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/IProjectNameDbContext.cs new file mode 100644 index 000000000..b9abdef0c --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/IProjectNameDbContext.cs @@ -0,0 +1,9 @@ +using Volo.Abp.Data; +using Volo.Abp.EntityFrameworkCore; + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; + +[ConnectionStringName(ProjectNameDbProperties.ConnectionStringName)] +public interface IProjectNameDbContext : IEfCoreDbContext +{ +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbContext.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbContext.cs new file mode 100644 index 000000000..5e43ea730 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbContext.cs @@ -0,0 +1,21 @@ +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Data; +using Volo.Abp.EntityFrameworkCore; + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; + +[ConnectionStringName(ProjectNameDbProperties.ConnectionStringName)] +public class ProjectNameDbContext : AbpDbContext, IProjectNameDbContext +{ + public ProjectNameDbContext( + DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + modelBuilder.ConfigureProjectName(); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbContextFactory.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbContextFactory.cs new file mode 100644 index 000000000..04338731b --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbContextFactory.cs @@ -0,0 +1,49 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Design; +using Microsoft.Extensions.Configuration; +using System.IO; + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; +public class ProjectNameDbContextFactory : IDesignTimeDbContextFactory +{ + public ProjectNameDbContext CreateDbContext(string[] args) + { + var configuration = BuildConfiguration(); + var connectionString = configuration.GetConnectionString("ProjectName"); + + DbContextOptionsBuilder builder = null; + +#if MySQL + builder = new DbContextOptionsBuilder() + .UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); +#elif SqlServer + builder = new DbContextOptionsBuilder() + .UseSqlServer(connectionString); +#elif Sqlite + builder = new DbContextOptionsBuilder() + .UseSqlite(connectionString); +#elif Oracle + builder = new DbContextOptionsBuilder() + .UseOracle(connectionString); +#elif OracleDevart + builder = (DbContextOptionsBuilder) new DbContextOptionsBuilder() + .UseOracle(connectionString); +#elif PostgreSql + builder = new DbContextOptionsBuilder() + .UseNpgsql(connectionString); +#endif + + return new ProjectNameDbContext(builder!.Options); + } + + private static IConfigurationRoot BuildConfiguration() + { + var builder = new ConfigurationBuilder() + .SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../PackageName.CompanyName.ProjectName.DbMigrator/")) + .AddJsonFile("appsettings.json", optional: false) + .AddJsonFile("appsettings.Development.json", optional: true); + + return builder.Build(); + } +} + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbContextModelCreatingExtensions.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbContextModelCreatingExtensions.cs new file mode 100644 index 000000000..f812977e6 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbContextModelCreatingExtensions.cs @@ -0,0 +1,21 @@ +using Microsoft.EntityFrameworkCore; +using System; +using Volo.Abp; + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; + +public static class ProjectNameDbContextModelCreatingExtensions +{ + public static void ConfigureProjectName( + this ModelBuilder builder, + Action optionsAction = null) + { + Check.NotNull(builder, nameof(builder)); + + var options = new ProjectNameModelBuilderConfigurationOptions( + ProjectNameDbProperties.DbTablePrefix, + ProjectNameDbProperties.DbSchema + ); + optionsAction?.Invoke(options); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbMigrationService.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbMigrationService.cs new file mode 100644 index 000000000..ea4490372 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameDbMigrationService.cs @@ -0,0 +1,234 @@ +using LINGYUN.Abp.Data.DbMigrator; +using LINGYUN.Abp.Saas.Tenants; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using PackageName.CompanyName.ProjectName.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using Volo.Abp.Data; +using Volo.Abp.DependencyInjection; +using Volo.Abp.MultiTenancy; + +namespace PackageName.CompanyName.ProjectName.DbMigrator.EntityFrameworkCore; + +public class ProjectNameDbMigrationService : ITransientDependency +{ + public ILogger Logger { get; set; } + + private readonly IDataSeeder _dataSeeder; + private readonly IDbSchemaMigrator _dbSchemaMigrator; + private readonly ITenantRepository _tenantRepository; + private readonly ICurrentTenant _currentTenant; + + public ProjectNameDbMigrationService( + IDataSeeder dataSeeder, + IDbSchemaMigrator dbSchemaMigrator, + ITenantRepository tenantRepository, + ICurrentTenant currentTenant) + { + _dataSeeder = dataSeeder; + _dbSchemaMigrator = dbSchemaMigrator; + _tenantRepository = tenantRepository; + _currentTenant = currentTenant; + + Logger = NullLogger.Instance; + } + + public async Task MigrateAsync() + { + var initialMigrationAdded = AddInitialMigrationIfNotExist(); + + if (initialMigrationAdded) + { + return; + } + + Logger.LogInformation("Started database migrations..."); + + await MigrateDatabaseSchemaAsync(); + await SeedDataAsync(); + + Logger.LogInformation($"Successfully completed host database migrations."); + + var tenants = await _tenantRepository.GetListAsync(includeDetails: true); + + var migratedDatabaseSchemas = new HashSet(); + foreach (var tenant in tenants) + { + using (_currentTenant.Change(tenant.Id)) + { + if (tenant.ConnectionStrings.Any()) + { + var tenantConnectionStrings = tenant.ConnectionStrings + .Select(x => x.Value) + .ToList(); + + if (!migratedDatabaseSchemas.IsSupersetOf(tenantConnectionStrings)) + { + await MigrateDatabaseSchemaAsync(tenant); + + migratedDatabaseSchemas.AddIfNotContains(tenantConnectionStrings); + } + } + + await SeedDataAsync(tenant); + } + + Logger.LogInformation($"Successfully completed {tenant.Name} tenant database migrations."); + } + + Logger.LogInformation("Successfully completed all database migrations."); + Logger.LogInformation("You can safely end this process..."); + } + + private async Task MigrateDatabaseSchemaAsync(Tenant? tenant = null) + { + Logger.LogInformation($"Migrating schema for {(tenant == null ? "host" : tenant.Name + " tenant")} database..."); + // 迁移租户数据 + await _dbSchemaMigrator.MigrateAsync( + (connectionString, builder) => + { +#if MySQL + builder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)); +#elif SqlServer + builder.UseSqlServer(connectionString); +#elif Sqlite + builder.UseSqlite(connectionString); +#elif Oracle + builder.UseOracle(connectionString); +#elif OracleDevart + builder.UseOracle(connectionString); +#elif PostgreSql + builder.UseNpgsql(connectionString); +#endif + + return new ProjectNameDbContext(builder.Options); + }); + } + + private async Task SeedDataAsync(Tenant? tenant = null) + { + Logger.LogInformation($"Executing {(tenant == null ? "host" : tenant.Name + " tenant")} database seed..."); + + await _dataSeeder.SeedAsync(tenant?.Id); + } + + private bool AddInitialMigrationIfNotExist() + { + try + { + if (!DbMigrationsProjectExists()) + { + return false; + } + } + catch (Exception) + { + return false; + } + + try + { + if (!MigrationsFolderExists()) + { + AddInitialMigration(); + return true; + } + else + { + return false; + } + } + catch (Exception e) + { + Logger.LogWarning("Couldn't determinate if any migrations exist : " + e.Message); + return false; + } + } + + private bool DbMigrationsProjectExists() + { + return Directory.Exists(GetEntityFrameworkCoreProjectFolderPath()); + } + + private bool MigrationsFolderExists() + { + var dbMigrationsProjectFolder = GetEntityFrameworkCoreProjectFolderPath(); + + return Directory.Exists(Path.Combine(dbMigrationsProjectFolder, "Migrations")); + } + + private void AddInitialMigration() + { + Logger.LogInformation("Creating initial migration..."); + + string argumentPrefix; + string fileName; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + argumentPrefix = "-c"; + fileName = "/bin/bash"; + } + else + { + argumentPrefix = "/C"; + fileName = "cmd.exe"; + } + + var procStartInfo = new ProcessStartInfo(fileName, + $"{argumentPrefix} \"abp create-migration-and-run-migrator \"{GetEntityFrameworkCoreProjectFolderPath()}\" --nolayers\"" + ); + + try + { + Process.Start(procStartInfo); + } + catch (Exception) + { + throw new Exception("Couldn't run ABP CLI..."); + } + } + + private string GetEntityFrameworkCoreProjectFolderPath() + { + var slnDirectoryPath = GetSolutionDirectoryPath(); + + if (slnDirectoryPath == null) + { + throw new Exception("Solution folder not found!"); + } + + return Path.Combine(slnDirectoryPath, "PackageName.CompanyName.ProjectName.HttpApi.Host"); + } + + private string? GetSolutionDirectoryPath() + { + var currentDirectory = new DirectoryInfo(Directory.GetCurrentDirectory()); + + while (Directory.GetParent(currentDirectory.FullName) != null) + { + currentDirectory = Directory.GetParent(currentDirectory.FullName); + + if (Directory.GetFiles(currentDirectory!.FullName).FirstOrDefault(f => f.EndsWith(".sln")) != null) + { + return currentDirectory.FullName; + } + + // parent host + currentDirectory = Directory.GetParent(currentDirectory.FullName); + if (Directory.GetFiles(currentDirectory!.FullName).FirstOrDefault(f => f.EndsWith(".sln")) != null) + { + return currentDirectory.FullName; + } + } + + return null; + } +} \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEfCoreQueryableExtensions.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEfCoreQueryableExtensions.cs new file mode 100644 index 000000000..eb9a9214b --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEfCoreQueryableExtensions.cs @@ -0,0 +1,6 @@ +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; + +public static class ProjectNameEfCoreQueryableExtensions +{ + // 在此聚合仓储服务的扩展方法 +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreModule.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreModule.cs new file mode 100644 index 000000000..71bab6e63 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreModule.cs @@ -0,0 +1,65 @@ +using LINGYUN.Abp.Data.DbMigrator; +using LINGYUN.Abp.Saas.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Modularity; +#if MySQL +using Volo.Abp.EntityFrameworkCore.MySQL; +#elif SqlServer +using Volo.Abp.EntityFrameworkCore.SqlServer; +#elif Sqlite +using Volo.Abp.EntityFrameworkCore.Sqlite; +#elif Oracle +using Volo.Abp.EntityFrameworkCore.Oracle; +#elif OracleDevart +using Volo.Abp.EntityFrameworkCore.Oracle.Devart; +#elif PostgreSql +using Volo.Abp.EntityFrameworkCore.PostgreSql; +#endif + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; + +[DependsOn( + typeof(ProjectNameDomainModule), + typeof(AbpDataDbMigratorModule), + typeof(AbpEntityFrameworkCoreModule), +#if MySQL + typeof(AbpEntityFrameworkCoreMySQLModule), +#elif SqlServer + typeof(AbpEntityFrameworkCoreSqlServerModule), +#elif Sqlite + typeof(AbpEntityFrameworkCoreSqliteModule), +#elif Oracle + typeof(AbpEntityFrameworkCoreOracleModule), +#elif OracleDevart + typeof(AbpEntityFrameworkCoreOracleDevartModule), +#elif PostgreSql + typeof(AbpEntityFrameworkCorePostgreSqlModule), +#endif + typeof(AbpSaasEntityFrameworkCoreModule))] +public class ProjectNameEntityFrameworkCoreModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + // 配置Ef + Configure(options => + { +#if MySQL + options.UseMySQL(); +#elif SqlServer + options.UseSqlServer(); +#elif Sqlite + options.UseSqlite(); +#elif Oracle || OracleDevart + options.UseOracle(); +#elif PostgreSql + options.UseNpgsql(); +#endif + }); + + context.Services.AddAbpDbContext(options => + { + options.AddDefaultRepositories(); + }); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameModelBuilderConfigurationOptions.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameModelBuilderConfigurationOptions.cs new file mode 100644 index 000000000..ba62d48a8 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.EntityFrameworkCore/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameModelBuilderConfigurationOptions.cs @@ -0,0 +1,17 @@ +using JetBrains.Annotations; +using Volo.Abp.EntityFrameworkCore.Modeling; + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore; + +public class ProjectNameModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions +{ + public ProjectNameModelBuilderConfigurationOptions( + [NotNull] string tablePrefix = "", + [CanBeNull] string schema = null) + : base( + tablePrefix, + schema) + { + + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/FodyWeavers.xml b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/FodyWeavers.xsd b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/PackageName.CompanyName.ProjectName.HttpApi.Client.csproj b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/PackageName.CompanyName.ProjectName.HttpApi.Client.csproj new file mode 100644 index 000000000..3931245c0 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/PackageName.CompanyName.ProjectName.HttpApi.Client.csproj @@ -0,0 +1,19 @@ + + + + + + + netstandard2.0 + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/PackageName/CompanyName/ProjectName/ProjectNameHttpApiClientModule.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/PackageName/CompanyName/ProjectName/ProjectNameHttpApiClientModule.cs new file mode 100644 index 000000000..ea6a14c25 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi.Client/PackageName/CompanyName/ProjectName/ProjectNameHttpApiClientModule.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Http.Client; +using Volo.Abp.Modularity; + +namespace PackageName.CompanyName.ProjectName; + +[DependsOn( + typeof(AbpHttpClientModule), + typeof(ProjectNameApplicationContractsModule))] +public class ProjectNameHttpApiClientModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddHttpClientProxies( + typeof(ProjectNameApplicationContractsModule).Assembly, + ProjectNameRemoteServiceConsts.RemoteServiceName); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/FodyWeavers.xml b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/FodyWeavers.xsd b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName.CompanyName.ProjectName.HttpApi.csproj b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName.CompanyName.ProjectName.HttpApi.csproj new file mode 100644 index 000000000..1cc138d19 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName.CompanyName.ProjectName.HttpApi.csproj @@ -0,0 +1,20 @@ + + + + + + + net7.0 + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName/CompanyName/ProjectName/ProjectNameControllerBase.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName/CompanyName/ProjectName/ProjectNameControllerBase.cs new file mode 100644 index 000000000..6797f475c --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName/CompanyName/ProjectName/ProjectNameControllerBase.cs @@ -0,0 +1,12 @@ +using PackageName.CompanyName.ProjectName.Localization; +using Volo.Abp.AspNetCore.Mvc; + +namespace PackageName.CompanyName.ProjectName; + +public abstract class ProjectNameControllerBase : AbpControllerBase +{ + protected ProjectNameControllerBase() + { + LocalizationResource = typeof(ProjectNameResource); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName/CompanyName/ProjectName/ProjectNameDynamicQueryableControllerBase.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName/CompanyName/ProjectName/ProjectNameDynamicQueryableControllerBase.cs new file mode 100644 index 000000000..865145f86 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName/CompanyName/ProjectName/ProjectNameDynamicQueryableControllerBase.cs @@ -0,0 +1,17 @@ +using LINGYUN.Abp.Dynamic.Queryable; +using PackageName.CompanyName.ProjectName.Localization; + +namespace PackageName.CompanyName.ProjectName; +/// +/// 提供动态查询控制器实现 +/// +/// 实体dto类型 +public abstract class ProjectNameDynamicQueryableControllerBase : DynamicQueryableControllerBase +{ + protected ProjectNameDynamicQueryableControllerBase( + IDynamicQueryableAppService service) + : base(service) + { + LocalizationResource = typeof(ProjectNameResource); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName/CompanyName/ProjectName/ProjectNameHttpApiModule.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName/CompanyName/ProjectName/ProjectNameHttpApiModule.cs new file mode 100644 index 000000000..90dccd31c --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.HttpApi/PackageName/CompanyName/ProjectName/ProjectNameHttpApiModule.cs @@ -0,0 +1,42 @@ +using PackageName.CompanyName.ProjectName.Localization; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.Localization; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.Validation.Localization; +using LINGYUN.Abp.Dynamic.Queryable; + +namespace PackageName.CompanyName.ProjectName; + +[DependsOn( + typeof(AbpAspNetCoreMvcModule), + typeof(ProjectNameApplicationContractsModule), + typeof(AbpDynamicQueryableHttpApiModule))] +public class ProjectNameHttpApiModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(ProjectNameHttpApiModule).Assembly); + }); + + PreConfigure(options => + { + options.AddAssemblyResource( + typeof(ProjectNameResource), + typeof(ProjectNameApplicationContractsModule).Assembly); + }); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Resources + .Get() + .AddBaseTypes(typeof(AbpValidationResource)); + }); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/FodyWeavers.xml b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/FodyWeavers.xml new file mode 100644 index 000000000..1715698cc --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/FodyWeavers.xsd b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/FodyWeavers.xsd new file mode 100644 index 000000000..11da52550 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/FodyWeavers.xsd @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed. + + + + + A comma-separated list of error codes that can be safely ignored in assembly verification. + + + + + 'false' to turn off automatic generation of the XML Schema file. + + + + + \ No newline at end of file diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName.CompanyName.ProjectName.SettingManagement.csproj b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName.CompanyName.ProjectName.SettingManagement.csproj new file mode 100644 index 000000000..965086211 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName.CompanyName.ProjectName.SettingManagement.csproj @@ -0,0 +1,21 @@ + + + + + + + net7.0 + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/IProjectNameSettingAppService.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/IProjectNameSettingAppService.cs new file mode 100644 index 000000000..308135ed0 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/IProjectNameSettingAppService.cs @@ -0,0 +1,7 @@ +using LINGYUN.Abp.SettingManagement; + +namespace PackageName.CompanyName.ProjectName.SettingManagement; + +public interface IProjectNameSettingAppService : ISettingAppService, IUserSettingAppService +{ +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/ProjectNameSettingAppService.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/ProjectNameSettingAppService.cs new file mode 100644 index 000000000..52641171c --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/ProjectNameSettingAppService.cs @@ -0,0 +1,106 @@ +using LINGYUN.Abp.SettingManagement; +using Microsoft.AspNetCore.Authorization; +using PackageName.CompanyName.ProjectName.Authorization; +using PackageName.CompanyName.ProjectName.Localization; +using System.Threading.Tasks; +using Volo.Abp.Application.Services; +using Volo.Abp.Features; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SettingManagement; +using Volo.Abp.Settings; +using Volo.Abp.Users; + +namespace PackageName.CompanyName.ProjectName.SettingManagement; + +public class ProjectNameSettingAppService : ApplicationService, IProjectNameSettingAppService +{ + protected ISettingManager SettingManager { get; } + protected ISettingDefinitionManager SettingDefinitionManager { get; } + + public ProjectNameSettingAppService( + ISettingManager settingManager, + ISettingDefinitionManager settingDefinitionManager) + { + SettingManager = settingManager; + SettingDefinitionManager = settingDefinitionManager; + LocalizationResource = typeof(ProjectNameResource); + } + + public virtual async Task GetAllForCurrentTenantAsync() + { + return await GetAllForProviderAsync(TenantSettingValueProvider.ProviderName, CurrentTenant.GetId().ToString()); + } + + [Authorize] + public virtual async Task GetAllForCurrentUserAsync() + { + return await GetAllForProviderAsync(UserSettingValueProvider.ProviderName, CurrentUser.GetId().ToString()); + } + + public virtual async Task GetAllForGlobalAsync() + { + return await GetAllForProviderAsync(GlobalSettingValueProvider.ProviderName, null); + } + + [Authorize(ProjectNamePermissions.ManageSettings)] + public virtual async Task SetCurrentTenantAsync(UpdateSettingsDto input) + { + // 增加特性检查 + await CheckFeatureAsync(); + + if (CurrentTenant.IsAvailable) + { + foreach (var setting in input.Settings) + { + await SettingManager.SetForTenantAsync(CurrentTenant.GetId(), setting.Name, setting.Value); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + } + } + + [Authorize] + public virtual async Task SetCurrentUserAsync(UpdateSettingsDto input) + { + // 增加特性检查 + await CheckFeatureAsync(); + + foreach (var setting in input.Settings) + { + await SettingManager.SetForCurrentUserAsync(setting.Name, setting.Value); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + [Authorize(ProjectNamePermissions.ManageSettings)] + public virtual async Task SetGlobalAsync(UpdateSettingsDto input) + { + // 增加特性检查 + await CheckFeatureAsync(); + + foreach (var setting in input.Settings) + { + await SettingManager.SetGlobalAsync(setting.Name, setting.Value); + } + + await CurrentUnitOfWork.SaveChangesAsync(); + } + + + protected virtual async Task CheckFeatureAsync() + { + await FeatureChecker.CheckEnabledAsync(SettingManagementFeatures.Enable); + } + + protected virtual async Task GetAllForProviderAsync(string providerName, string providerKey) + { + var settingGroups = new SettingGroupResult(); + + //TODO: 当前项目所有配置项在此定义返回 + + await Task.CompletedTask; + + return settingGroups; + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/ProjectNameSettingController.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/ProjectNameSettingController.cs new file mode 100644 index 000000000..0351f10ad --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/ProjectNameSettingController.cs @@ -0,0 +1,68 @@ +using LINGYUN.Abp.SettingManagement; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using PackageName.CompanyName.ProjectName.Authorization; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.AspNetCore.Mvc; + +namespace PackageName.CompanyName.ProjectName.SettingManagement; + +[RemoteService(Name = ProjectNameRemoteServiceConsts.RemoteServiceName)] +[ApiVersion("2.0")] +[Area(ProjectNameRemoteServiceConsts.ModuleName)] +[Route("api/ProjectName/settings")] +public class ProjectNameSettingController : AbpController, IProjectNameSettingAppService +{ + private readonly IProjectNameSettingAppService _settingAppService; + public ProjectNameSettingController(IProjectNameSettingAppService settingAppService) + { + _settingAppService = settingAppService; + } + + [Authorize(ProjectNamePermissions.ManageSettings)] + [HttpPut] + [Route("by-current-tenant")] + public virtual async Task SetCurrentTenantAsync(UpdateSettingsDto input) + { + await _settingAppService.SetCurrentTenantAsync(input); + } + + [HttpGet] + [Route("by-current-tenant")] + public virtual async Task GetAllForCurrentTenantAsync() + { + return await _settingAppService.GetAllForCurrentTenantAsync(); + } + + [Authorize] + [HttpPut] + [Route("by-current-user")] + public virtual async Task SetCurrentUserAsync(UpdateSettingsDto input) + { + await _settingAppService.SetCurrentTenantAsync(input); + } + + [Authorize] + [HttpGet] + [Route("by-current-user")] + public virtual async Task GetAllForCurrentUserAsync() + { + return await _settingAppService.GetAllForCurrentTenantAsync(); + } + + [Authorize(ProjectNamePermissions.ManageSettings)] + [HttpPut] + [Route("by-global")] + public virtual async Task SetGlobalAsync(UpdateSettingsDto input) + { + await _settingAppService.SetGlobalAsync(input); + } + + [HttpGet] + [Route("by-global")] + public virtual async Task GetAllForGlobalAsync() + { + return await _settingAppService.GetAllForGlobalAsync(); + } +} diff --git a/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/ProjectNameSettingManagementModule.cs b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/ProjectNameSettingManagementModule.cs new file mode 100644 index 000000000..09eb20393 --- /dev/null +++ b/aspnet-core/templates/content/src/PackageName.CompanyName.ProjectName.SettingManagement/PackageName/CompanyName/ProjectName/SettingManagement/ProjectNameSettingManagementModule.cs @@ -0,0 +1,22 @@ +using LINGYUN.Abp.SettingManagement; +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.Modularity; +using Volo.Abp.SettingManagement; + +namespace PackageName.CompanyName.ProjectName.SettingManagement; + +[DependsOn( + typeof(AbpSettingManagementApplicationContractsModule), + typeof(AbpAspNetCoreMvcModule), + typeof(AbpSettingManagementDomainModule))] +public class ProjectNameSettingManagementModule : AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + PreConfigure(mvcBuilder => + { + mvcBuilder.AddApplicationPartIfNotExists(typeof(ProjectNameSettingManagementModule).Assembly); + }); + } +} diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName.CompanyName.ProjectName.Application.Tests.csproj b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName.CompanyName.ProjectName.Application.Tests.csproj new file mode 100644 index 000000000..f22579773 --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName.CompanyName.ProjectName.Application.Tests.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + + false + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/ProjectNameApplicationTestBase.cs b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/ProjectNameApplicationTestBase.cs new file mode 100644 index 000000000..81ea710fc --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/ProjectNameApplicationTestBase.cs @@ -0,0 +1,6 @@ +namespace PackageName.CompanyName.ProjectName +{ + public abstract class ProjectNameApplicationTestBase : ProjectNameTestBase + { + } +} diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/ProjectNameApplicationTestModule.cs b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/ProjectNameApplicationTestModule.cs new file mode 100644 index 000000000..6d74be333 --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Application.Tests/PackageName/CompanyName/ProjectName/ProjectNameApplicationTestModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Modularity; + +namespace PackageName.CompanyName.ProjectName +{ + [DependsOn( + typeof(ProjectNameDomainTestModule), + typeof(ProjectNameApplicationModule) + )] + public class ProjectNameApplicationTestModule : AbpModule + { + } +} diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName.CompanyName.ProjectName.Domain.Tests.csproj b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName.CompanyName.ProjectName.Domain.Tests.csproj new file mode 100644 index 000000000..45a33d2f7 --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName.CompanyName.ProjectName.Domain.Tests.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + + false + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName/CompanyName/ProjectName/ProjectNameDomainTestBase.cs b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName/CompanyName/ProjectName/ProjectNameDomainTestBase.cs new file mode 100644 index 000000000..f33c7a00d --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName/CompanyName/ProjectName/ProjectNameDomainTestBase.cs @@ -0,0 +1,6 @@ +namespace PackageName.CompanyName.ProjectName +{ + public abstract class ProjectNameDomainTestBase : ProjectNameTestBase + { + } +} diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName/CompanyName/ProjectName/ProjectNameDomainTestModule.cs b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName/CompanyName/ProjectName/ProjectNameDomainTestModule.cs new file mode 100644 index 000000000..16404a73f --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.Domain.Tests/PackageName/CompanyName/ProjectName/ProjectNameDomainTestModule.cs @@ -0,0 +1,12 @@ +using Volo.Abp.Modularity; + +namespace PackageName.CompanyName.ProjectName +{ + [DependsOn( + typeof(ProjectNameTestBaseModule), + typeof(ProjectNameDomainModule) + )] + public class ProjectNameDomainTestModule : AbpModule + { + } +} diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests.csproj b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests.csproj new file mode 100644 index 000000000..d402ff4e3 --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests.csproj @@ -0,0 +1,19 @@ + + + + net7.0 + + false + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreTestBase.cs b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreTestBase.cs new file mode 100644 index 000000000..7fd73c607 --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreTestBase.cs @@ -0,0 +1,6 @@ +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore +{ + public abstract class ProjectNameEntityFrameworkCoreTestBase : ProjectNameTestBase + { + } +} diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreTestModule.cs b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreTestModule.cs new file mode 100644 index 000000000..39f7d3e43 --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.EntityFrameworkCore.Tests/PackageName/CompanyName/ProjectName/EntityFrameworkCore/ProjectNameEntityFrameworkCoreTestModule.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using System; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Modularity; +using Volo.Abp.Uow; + +namespace PackageName.CompanyName.ProjectName.EntityFrameworkCore +{ + [DependsOn( + typeof(ProjectNameTestBaseModule), + typeof(ProjectNameEntityFrameworkCoreModule) + )] + public class ProjectNameEntityFrameworkCoreTestModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddEntityFrameworkInMemoryDatabase(); + + var databaseName = Guid.NewGuid().ToString(); + + Configure(options => + { + options.Configure(abpDbContextConfigurationContext => + { + abpDbContextConfigurationContext.DbContextOptions.EnableDetailedErrors(); + abpDbContextConfigurationContext.DbContextOptions.EnableSensitiveDataLogging(); + + abpDbContextConfigurationContext.DbContextOptions.UseInMemoryDatabase(databaseName); + }); + }); + + Configure(options => + { + options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; //EF in-memory database does not support transactions + }); + } + } +} diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName.CompanyName.ProjectName.TestBase.csproj b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName.CompanyName.ProjectName.TestBase.csproj new file mode 100644 index 000000000..08a729680 --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName.CompanyName.ProjectName.TestBase.csproj @@ -0,0 +1,23 @@ + + + + net7.0 + + false + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName/CompanyName/ProjectName/ProjectNameTestBase.cs b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName/CompanyName/ProjectName/ProjectNameTestBase.cs new file mode 100644 index 000000000..825525f0a --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName/CompanyName/ProjectName/ProjectNameTestBase.cs @@ -0,0 +1,59 @@ +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Threading.Tasks; +using Volo.Abp; +using Volo.Abp.Modularity; +using Volo.Abp.Testing; +using Volo.Abp.Uow; + +namespace PackageName.CompanyName.ProjectName +{ + public abstract class ProjectNameTestBase : AbpIntegratedTest + where TStartupModule : IAbpModule + { + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.UseAutofac(); + } + + protected virtual Task WithUnitOfWorkAsync(Func func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func action) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + await action(); + + await uow.CompleteAsync(); + } + } + } + + protected virtual Task WithUnitOfWorkAsync(Func> func) + { + return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); + } + + protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func> func) + { + using (var scope = ServiceProvider.CreateScope()) + { + var uowManager = scope.ServiceProvider.GetRequiredService(); + + using (var uow = uowManager.Begin(options)) + { + var result = await func(); + await uow.CompleteAsync(); + return result; + } + } + } + } +} diff --git a/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName/CompanyName/ProjectName/ProjectNameTestBaseModule.cs b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName/CompanyName/ProjectName/ProjectNameTestBaseModule.cs new file mode 100644 index 000000000..a24ec432c --- /dev/null +++ b/aspnet-core/templates/content/tests/PackageName.CompanyName.ProjectName.TestBase/PackageName/CompanyName/ProjectName/ProjectNameTestBaseModule.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp; +using Volo.Abp.Authorization; +using Volo.Abp.Autofac; +using Volo.Abp.Features; +using Volo.Abp.MemoryDb; +using Volo.Abp.Modularity; + +namespace PackageName.CompanyName.ProjectName +{ + [DependsOn( + typeof(AbpAutofacModule), + typeof(AbpTestBaseModule), + typeof(AbpAuthorizationModule), + typeof(AbpFeaturesModule), + typeof(AbpMemoryDbModule) + )] + public class ProjectNameTestBaseModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAlwaysAllowAuthorization(); + } + } +}