Skip to content

Commit

Permalink
Merge pull request #9 from abpframework/containerization-to-deploy
Browse files Browse the repository at this point in the history
Deploy CMS Kit Demo application to cms-kit-demo.abpdemo.com
  • Loading branch information
EngincanV authored May 15, 2024
2 parents 69aef33 + f025c6d commit 6bc3619
Show file tree
Hide file tree
Showing 19 changed files with 652 additions and 21 deletions.
60 changes: 60 additions & 0 deletions .github/workflows/containerization-to-deploy_cms-kit-demo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# # Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# # More GitHub Actions for Azure: https://github.com/Azure/actions

# name: Build and deploy ASP.Net Core app to Azure Web App - cms-kit-demo

# on:
# push:
# branches:
# - containerization-to-deploy
# workflow_dispatch:

# jobs:
# build:
# runs-on: ubuntu-latest

# steps:
# - uses: actions/checkout@v2

# - name: Set up .NET Core
# uses: actions/setup-dotnet@v1
# with:
# dotnet-version: '7.x'
# include-prerelease: true

# - name: Build with dotnet
# run: dotnet build --configuration Release

# - name: dotnet publish
# run: dotnet publish -c Release -o ${{env.DOTNET_ROOT}}/myapp

# - name: Copy CmsKitDemo.db to publish directory
# run: cp src/CmsKitDemo.db ${{env.DOTNET_ROOT}}/myapp

# - name: Upload artifact for deployment job
# uses: actions/upload-artifact@v2
# with:
# name: .net-app
# path: ${{env.DOTNET_ROOT}}/myapp

# deploy:
# runs-on: ubuntu-latest
# needs: build
# environment:
# name: 'Production'
# url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}

# steps:
# - name: Download artifact from build job
# uses: actions/download-artifact@v2
# with:
# name: .net-app

# - name: Deploy to Azure Web App
# id: deploy-to-webapp
# uses: azure/webapps-deploy@v2
# with:
# app-name: 'cms-kit-demo'
# slot-name: 'Production'
# publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_B8EE580013C3409F9EA266AF29C41EAD }}
# package: .
3 changes: 3 additions & 0 deletions src/CmsKitDemo/CmsKitDemo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@
<Content Remove="Logs\**" />
<EmbeddedResource Remove="Logs\**" />
<None Remove="Logs\**" />
<None Update="CmsKitDemoDb\CmsKitDemo.db">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 2 additions & 0 deletions src/CmsKitDemo/CmsKitDemoConsts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class CmsKitDemoConsts
public const string ImageGalleryEntityType = "Image";

public const int MaxDescriptionLength = 512;

public static readonly List<string> IgnoredUserAgents = new();
}
}
File renamed without changes.
15 changes: 14 additions & 1 deletion src/CmsKitDemo/CmsKitDemoModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,11 @@
using Volo.CmsKit.Web;
using Volo.Abp.Threading;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Volo.Abp.Data;
using Volo.Abp.IO;
using Volo.CmsKit.Reactions;
using Volo.CmsKit.Comments;
using Microsoft.EntityFrameworkCore.Query;

namespace CmsKitDemo;

Expand Down Expand Up @@ -316,7 +319,8 @@ private void ConfigureEfCore(ServiceConfigurationContext context)
{
options.Configure(configurationContext =>
{
configurationContext.UseSqlite();
configurationContext.UseSqlite()
.ReplaceService<IMethodCallTranslatorProvider, CmsKitDemoSqliteMethodCallTranslatorProvider>();
});
});

Expand Down Expand Up @@ -358,6 +362,13 @@ private void ConfigureCmsKit(ServiceConfigurationContext context)
});
}

public override async Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
{
DirectoryHelper.CreateIfNotExists(context.GetConfiguration()["App:DbFolderName"] ?? "CmsKitDemoDb");
var connString = await context.ServiceProvider.GetRequiredService<IConnectionStringResolver>().ResolveAsync();
await context.ServiceProvider.GetRequiredService<CmsKitDemoDbMigrationService>().MigrateAsync(connString);
}

public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
Expand All @@ -375,6 +386,8 @@ public override void OnApplicationInitialization(ApplicationInitializationContex
app.UseErrorPage();
}

app.UseMiddleware<DbMigrationMiddleware>();

app.UseCorrelationId();
app.UseStaticFiles();
app.UseRouting();
Expand Down
53 changes: 53 additions & 0 deletions src/CmsKitDemo/Data/CmsKitConnectionStringResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Microsoft.Extensions.Options;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;

namespace CmsKitDemo.Data;

[Dependency(ReplaceServices = true)]
public class CmsKitConnectionStringResolver : DefaultConnectionStringResolver
{
private readonly CmsKitDemoUserIdResolver _demoNameResolver;
private readonly IConfiguration _configuration;

public CmsKitConnectionStringResolver(
IOptionsMonitor<AbpDbConnectionOptions> options,
CmsKitDemoUserIdResolver demoNameResolver,
IConfiguration configuration)
: base(options)
{
_demoNameResolver = demoNameResolver;
_configuration = configuration;
}

[Obsolete("Use ResolveAsync method.")]
public override string Resolve(string connectionStringName = null)
{
return AsyncHelper.RunSync(() => ResolveInternalAsync(connectionStringName));
}

public async override Task<string> ResolveAsync(string connectionStringName = null)
{
return await ResolveInternalAsync(connectionStringName);
}

private async Task<string> ResolveInternalAsync(string connectionStringName = null)
{
var dbFolder = _configuration["App:DbFolderName"]?.EnsureEndsWith(Path.DirectorySeparatorChar);
if (dbFolder.IsNullOrWhiteSpace())
{
return await base.ResolveAsync(connectionStringName);
}

var demoUserId = _demoNameResolver.GetDemoUserIdOrNull() ?? _configuration["App:DefaultDbName"];

var dbFilePath = $"{dbFolder}{demoUserId}.db";
if (!File.Exists(dbFilePath))
{
File.Copy(_configuration["App:DbFolderName"]?.EnsureEndsWith(Path.DirectorySeparatorChar) + _configuration["App:DefaultDbName"] + ".db", dbFilePath);
}

return $"Data Source={dbFilePath};Cache=Shared";
}
}
5 changes: 3 additions & 2 deletions src/CmsKitDemo/Data/CmsKitDemoDbContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ public class CmsKitDemoDbContextFactory : IDesignTimeDbContextFactory<CmsKitDemo
{
public CmsKitDemoDbContext CreateDbContext(string[] args)
{

var configuration = BuildConfiguration();

var dbFolder = configuration["App:DbFolderName"]!.EnsureEndsWith(Path.DirectorySeparatorChar);

var builder = new DbContextOptionsBuilder<CmsKitDemoDbContext>()
.UseSqlite(configuration.GetConnectionString("Default"));
.UseSqlite($"Data Source={dbFolder}{configuration["App:DefaultDbName"]}.db;");

return new CmsKitDemoDbContext(builder.Options);
}
Expand Down
54 changes: 52 additions & 2 deletions src/CmsKitDemo/Data/CmsKitDemoDbMigrationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,73 @@ public class CmsKitDemoDbMigrationService : ITransientDependency
private readonly CmsKitDemoEFCoreDbSchemaMigrator _dbSchemaMigrator;
private readonly ITenantRepository _tenantRepository;
private readonly ICurrentTenant _currentTenant;
private readonly IConfiguration _configuration;

public CmsKitDemoDbMigrationService(
IDataSeeder dataSeeder,
CmsKitDemoEFCoreDbSchemaMigrator dbSchemaMigrator,
ITenantRepository tenantRepository,
ICurrentTenant currentTenant)
ICurrentTenant currentTenant,
IConfiguration configuration)
{
_dataSeeder = dataSeeder;
_dbSchemaMigrator = dbSchemaMigrator;
_tenantRepository = tenantRepository;
_currentTenant = currentTenant;
_configuration = configuration;

Logger = NullLogger<CmsKitDemoDbMigrationService>.Instance;
}

private async Task MigrateHostDatabaseAsync(string connectionString)
{
Logger.LogInformation("Migrating host database schema...");

if (!connectionString.Contains(_configuration["App:DefaultDbName"] + ".db"))
{
TryToCopyFromDefaultDb(connectionString);
}
else
{
await _dbSchemaMigrator.MigrateAsync(connectionString);
}

public async Task MigrateAsync()
Logger.LogInformation("Executing host database seed...");

await _dataSeeder.SeedAsync(
new DataSeedContext()
.WithProperty("AdminPassword", "123456")
);

Logger.LogInformation("Successfully completed host database migrations.");
}

private void TryToCopyFromDefaultDb(string connectionString)
{
try
{
var filePath = connectionString!.Replace("Data Source=", "").Split(";")[0];
File.Copy(_configuration["App:DbFolderName"]?.EnsureEndsWith(Path.DirectorySeparatorChar) + _configuration["App:DefaultDbName"] + ".db", filePath);
}
catch
{
//...
}
}

public async Task MigrateAsync(string? connectionString = null)
{
if (!connectionString.IsNullOrWhiteSpace())
{
Logger.LogInformation("Started database migrations...");

await MigrateHostDatabaseAsync(connectionString!);

Logger.LogInformation("Successfully completed database migrations.");

return;
}

var initialMigrationAdded = AddInitialMigrationIfNotExist();

if (initialMigrationAdded)
Expand Down
29 changes: 16 additions & 13 deletions src/CmsKitDemo/Data/CmsKitDemoEFCoreDbSchemaMigrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,26 @@ public class CmsKitDemoEFCoreDbSchemaMigrator : ITransientDependency
{
private readonly IServiceProvider _serviceProvider;

public CmsKitDemoEFCoreDbSchemaMigrator(
IServiceProvider serviceProvider)
public CmsKitDemoEFCoreDbSchemaMigrator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

public async Task MigrateAsync()
public async Task MigrateAsync(string? connectionString = null)
{
/* We intentionally resolve the CmsKitDemoDbContext
* from IServiceProvider (instead of directly injecting it)
* to properly get the connection string of the current tenant in the
* current scope.
*/
if (connectionString.IsNullOrWhiteSpace())
{
await _serviceProvider.GetRequiredService<CmsKitDemoDbContext>().Database.MigrateAsync();
return;
}

await _serviceProvider
.GetRequiredService<CmsKitDemoDbContext>()
.Database
.MigrateAsync();
var options = new DbContextOptionsBuilder<CmsKitDemoDbContext>()
.UseSqlite(connectionString)
.Options;

using (var dbContext = new CmsKitDemoDbContext(options))
{
await dbContext.Database.MigrateAsync();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
using Microsoft.EntityFrameworkCore.Sqlite.Query.Internal;
using System.Reflection;
using Volo.Abp;

namespace CmsKitDemo.Data
{
public class CmsKitDemoSqliteMethodCallTranslatorProvider : SqliteMethodCallTranslatorProvider
{
public CmsKitDemoSqliteMethodCallTranslatorProvider([NotNull] RelationalMethodCallTranslatorProviderDependencies dependencies)
: base(dependencies)
{
var sqlExpressionFactory = dependencies.SqlExpressionFactory;

AddTranslators(
new IMethodCallTranslator[]
{
new SqliteMathTranslator(sqlExpressionFactory),
new SqliteDateTimeAddTranslator(sqlExpressionFactory.As<SqliteSqlExpressionFactory>()),
new CmsKitDemoSqliteStringMethodTranslator(sqlExpressionFactory)
});
}
}

public class CmsKitDemoSqliteStringMethodTranslator : SqliteStringMethodTranslator
{
private static readonly MethodInfo _containsMethodInfo
= typeof(string).GetRuntimeMethod(nameof(string.Contains), new[] { typeof(string) });

private readonly ISqlExpressionFactory _sqlExpressionFactory;

public CmsKitDemoSqliteStringMethodTranslator(ISqlExpressionFactory sqlExpressionFactory) : base(sqlExpressionFactory)
{
_sqlExpressionFactory = sqlExpressionFactory;
}

public override SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList<SqlExpression> arguments, IDiagnosticsLogger<DbLoggerCategory.Query> logger)
{
Check.NotNull(method, nameof(method));
Check.NotNull(arguments, nameof(arguments));

if (_containsMethodInfo.Equals(method))
{
var pattern = arguments[0];
var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern);

instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);
pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping);

// this basically changes query to "instr(upper(left_expression), upper(right_expression))"
return _sqlExpressionFactory.OrElse(
_sqlExpressionFactory.Equal(
pattern,
_sqlExpressionFactory.Constant(string.Empty, stringTypeMapping)),
_sqlExpressionFactory.GreaterThan(
_sqlExpressionFactory.Function(
"instr",
new[]
{
_sqlExpressionFactory.Function("upper", new[]{instance}, false, new []{ false }, typeof(string)),
_sqlExpressionFactory.Function("upper", new[]{pattern}, false, new []{ false }, typeof(string))
},
false,
new[] { false, false },
typeof(int)), _sqlExpressionFactory.Constant(0)));
}

return base.Translate(instance, method, arguments, logger);
}
}
}
Loading

0 comments on commit 6bc3619

Please sign in to comment.