Skip to content

Commit

Permalink
code format && add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
qdraw committed Oct 13, 2024
1 parent 250a3c8 commit 0154cfc
Showing 1 changed file with 90 additions and 77 deletions.
167 changes: 90 additions & 77 deletions starsky/starsky.foundation.database/DataProtection/SqlXmlRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,116 +3,129 @@
using System.Linq;
using System.Xml.Linq;
using Microsoft.AspNetCore.DataProtection.Repositories;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using MySqlConnector;
using starsky.foundation.database.Data;
using starsky.foundation.database.Models;
using starsky.foundation.database.Query;
using starsky.foundation.injection;
using starsky.foundation.platform.Helpers;
using starsky.foundation.platform.Interfaces;

namespace starsky.foundation.database.DataProtection
namespace starsky.foundation.database.DataProtection;

/// <summary>
/// @see:
/// https://nicolas.guelpa.me/blog/2017/01/11/dotnet-core-data-protection-keys-repository.html
/// @see:
/// https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/introduction?view=aspnetcore-5.0
/// @see:
/// https://medium.com/@_kbremner/storing-asp-net-core-data-protection-keys-in-the-database-f284d13897b8
/// @see: https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/web-farm
/// </summary>
[Service(typeof(IXmlRepository), InjectionLifetime = InjectionLifetime.Scoped)]
public class SqlXmlRepository : IXmlRepository
{
[Service(typeof(IXmlRepository), InjectionLifetime = InjectionLifetime.Scoped)]
public class SqlXmlRepository : IXmlRepository
private readonly ApplicationDbContext _dbContext;
private readonly IWebLogger _logger;
private readonly IServiceScopeFactory _scopeFactory;

public SqlXmlRepository(ApplicationDbContext dbContext, IServiceScopeFactory scopeFactory,
IWebLogger logger)
{
private readonly ApplicationDbContext _dbContext;
private readonly IServiceScopeFactory _scopeFactory;
private readonly IWebLogger _logger;
_dbContext = dbContext;
_scopeFactory = scopeFactory;
_logger = logger;
}

public SqlXmlRepository(ApplicationDbContext dbContext, IServiceScopeFactory scopeFactory, IWebLogger logger)
public IReadOnlyCollection<XElement> GetAllElements()
{
try
{
_dbContext = dbContext;
_scopeFactory = scopeFactory;
_logger = logger;
}
var result = _dbContext.DataProtectionKeys
.Where(p => p.Xml != null).AsEnumerable()
.Select(x => XElement.Parse(x.Xml!)).ToList();

public IReadOnlyCollection<XElement> GetAllElements()
return result;
}
catch ( Exception exception )
{
try
if ( exception is not RetryLimitExceededException &&
exception is not MySqlException &&
exception is not SqliteException )
{
var result = _dbContext.DataProtectionKeys
.Where(p => p.Xml != null).AsEnumerable()
.Select(x => XElement.Parse(x.Xml!)).ToList();

return result;
throw;
}
catch ( Exception exception )
{
if ( exception is not RetryLimitExceededException &&
exception is not MySqlConnector.MySqlException &&
exception is not Microsoft.Data.Sqlite.SqliteException )
{
throw;
}

// MySqlConnector.MySqlException (0x80004005): Table 'starsky.DataProtectionKeys' doesn't exist
// or Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 1: 'no such table: DataProtectionKeys
if ( !exception.Message.Contains("0x80004005") &&
!exception.Message.Contains(
"no such table: DataProtectionKeys") )
{
return new List<XElement>();
}

_logger.LogInformation("run migration: dotnet ef database update");
_dbContext.Database.Migrate();
// MySqlConnector.MySqlException (0x80004005): Table 'starsky.DataProtectionKeys' doesn't exist
// or Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 1: 'no such table: DataProtectionKeys
if ( !exception.Message.Contains("0x80004005") &&
!exception.Message.Contains(
"no such table: DataProtectionKeys") )
{
return new List<XElement>();
}

_logger.LogInformation("run migration: dotnet ef database update");
_dbContext.Database.Migrate();
return new List<XElement>();
}
}

/// <summary>
/// This function crashes usually on the first run
/// </summary>
/// <param name="element">Xml element</param>
/// <param name="friendlyName">name of item</param>
public void StoreElement(XElement element, string friendlyName)
/// <summary>
/// This function crashes usually on the first run
/// </summary>
/// <param name="element">Xml element</param>
/// <param name="friendlyName">name of item</param>
public void StoreElement(XElement element, string friendlyName)
{
bool LocalDefault(ApplicationDbContext ctx)
{
bool LocalDefault(ApplicationDbContext ctx)
ctx.DataProtectionKeys.Add(new DataProtectionKey
{
ctx.DataProtectionKeys.Add(new DataProtectionKey
{
Xml = element.ToString(SaveOptions.DisableFormatting),
FriendlyName = friendlyName
});
ctx.SaveChanges();
return true;
}
Xml = element.ToString(SaveOptions.DisableFormatting),
FriendlyName = friendlyName
});
ctx.SaveChanges();
return true;
}

bool LocalDefaultQuery()
{
var context = new InjectServiceScope(_scopeFactory).Context();
return LocalDefault(context);
}

bool LocalDefaultQuery()
try
{
LocalDefault(_dbContext);
}
catch ( Exception exception )
{
if ( exception is not DbUpdateException &&
exception is not RetryLimitExceededException &&
exception is not MySqlException &&
exception is not SqliteException )
{
var context = new InjectServiceScope(_scopeFactory).Context();
return LocalDefault(context);
throw;
}

var retryInterval = _dbContext.GetType().FullName?.Contains("test") == true
? TimeSpan.FromSeconds(0)
: TimeSpan.FromSeconds(5);

try
{
LocalDefault(_dbContext);
RetryHelper.Do(
LocalDefaultQuery, retryInterval, 2);
}
catch ( Exception exception )
catch ( AggregateException aggregateException )
{
if ( exception is not DbUpdateException &&
exception is not RetryLimitExceededException &&
exception is not MySqlConnector.MySqlException &&
exception is not Microsoft.Data.Sqlite.SqliteException )
{
throw;
}

var retryInterval = _dbContext.GetType().FullName?.Contains("test") == true ?
TimeSpan.FromSeconds(0) : TimeSpan.FromSeconds(5);

try
{
RetryHelper.Do(
LocalDefaultQuery, retryInterval, 2);
}
catch ( AggregateException aggregateException )
{
_logger.LogError(aggregateException, "[SqlXmlRepository] catch-ed AggregateException");
}
_logger.LogError(aggregateException,
"[SqlXmlRepository] catch-ed AggregateException");
}
}
}
Expand Down

0 comments on commit 0154cfc

Please sign in to comment.