Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions MobileConfiguration/MobileConfiguration.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
</PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.2" />
<PackageReference Include="NLog.Web.AspNetCore" Version="5.5.0" />
<PackageReference Include="Shared" Version="2025.6.2" />
<PackageReference Include="Shared.Results.Web" Version="2025.6.2" />
<PackageReference Include="Shared" Version="2025.7.2" />
<PackageReference Include="Shared.Results.Web" Version="2025.7.2" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.5">
Expand Down
33 changes: 12 additions & 21 deletions MobileConfiguration/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Host.UseWindowsService();
String path = Assembly.GetExecutingAssembly().Location;
path = Path.GetDirectoryName(path);

Check warning on line 28 in MobileConfiguration/Program.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

Converting null literal or possible null value to non-nullable type.
builder.Configuration.SetBasePath(path)

Check warning on line 29 in MobileConfiguration/Program.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

Possible null reference argument for parameter 'basePath' in 'IConfigurationBuilder FileConfigurationExtensions.SetBasePath(IConfigurationBuilder builder, string basePath)'.
.AddJsonFile("hosting.json", optional: true)
.AddJsonFile("hosting.development.json", optional: true)
.AddEnvironmentVariables();
Expand All @@ -37,22 +37,15 @@
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton<IConfigurationRepository, ConfigurationRepository>();
builder.Services.AddSingleton<IConnectionStringConfigurationRepository, ConfigurationReaderConnectionStringRepository>();
builder.Services.AddSingleton<Shared.EntityFramework.IDbContextFactory<ConfigurationContext>, DbContextFactory<ConfigurationContext>>();

builder.Services.AddSingleton(typeof(IDbContextResolver<>), typeof(DbContextResolver<>));
Boolean isInMemoryDatabase = Boolean.Parse(ConfigurationReader.GetValue("AppSettings", "InMemoryDatabase"));

if (isInMemoryDatabase) {
builder.Services.AddDbContext<ConfigurationContext>(builder => builder.UseInMemoryDatabase("ConfigurationDatabaseTest"));
DbContextOptionsBuilder<ConfigurationContext> contextBuilder = new DbContextOptionsBuilder<ConfigurationContext>();
contextBuilder = contextBuilder.UseInMemoryDatabase("ConfigurationDatabaseTest");
builder.Services.AddSingleton<Func<String, ConfigurationContext>>(cont => (connectionString) => new ConfigurationContext(contextBuilder.Options));
}
else {

String connectionString = ConfigurationReader.GetConnectionString("ConfigurationDatabase");
builder.Services.AddDbContext<ConfigurationContext>(builder => builder.UseSqlServer(connectionString));
builder.Services.AddSingleton<Func<String, ConfigurationContext>>(cont => (connectionString) => { return new ConfigurationContext(connectionString); });
builder.Services.AddDbContext<ConfigurationContext>(options =>
options.UseSqlServer(configuration.GetConnectionString("ConfigurationDatabase")));
}
bool logRequests = ConfigurationReaderExtensions.GetValueOrDefault<Boolean>("MiddlewareLogging", "LogRequests", true);
bool logResponses = ConfigurationReaderExtensions.GetValueOrDefault<Boolean>("MiddlewareLogging", "LogResponses", true);
Expand Down Expand Up @@ -82,8 +75,8 @@

var loggerFactory = app.Services.GetRequiredService<ILoggerFactory>();

loggerFactory.ConfigureNLog(Path.Combine(path, nlogConfigFilename));

Check warning on line 78 in MobileConfiguration/Program.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

'ConfigureExtensions.ConfigureNLog(ILoggerFactory, string)' is obsolete: 'Instead use NLog.LogManager.Setup().LoadConfigurationFromFile()'
loggerFactory.AddNLog();

Check warning on line 79 in MobileConfiguration/Program.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

'ConfigureExtensions.AddNLog(ILoggerFactory)' is obsolete: 'Instead use ILoggingBuilder.AddNLog() or IHostBuilder.UseNLog()'

ILogger logger = loggerFactory.CreateLogger("MobileConfiguration");

Expand All @@ -92,11 +85,12 @@

// Configure the HTTP request pipeline.
app.UseAuthorization();

app.UseMiddleware<CorrelationIdMiddleware>();
app.AddRequestLogging();
app.AddResponseLogging();
app.AddExceptionHandler();


app.MapControllers();

InitializeDatabase(app).Wait(CancellationToken.None);
Expand All @@ -106,7 +100,7 @@

async Task InitializeDatabase(IApplicationBuilder app)
{
using (IServiceScope serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())

Check warning on line 103 in MobileConfiguration/Program.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

Dereference of a possibly null reference.
{
ConfigurationContext dbContext = serviceScope.ServiceProvider.GetRequiredService<ConfigurationContext>();

Expand All @@ -117,23 +111,20 @@
}
}

public static class ConfigurationReaderExtensions
{
public static T GetValueOrDefault<T>(String sectionName, String keyName, T defaultValue)
{
try
{
public static class ConfigurationReaderExtensions {
public static T GetValueOrDefault<T>(String sectionName,
String keyName,
T defaultValue) {
try {
var value = ConfigurationReader.GetValue(sectionName, keyName);

if (String.IsNullOrEmpty(value))
{
if (String.IsNullOrEmpty(value)) {
return defaultValue;
}

return (T)Convert.ChangeType(value, typeof(T));
}
catch (KeyNotFoundException kex)
{
catch (KeyNotFoundException kex) {

Check warning on line 127 in MobileConfiguration/Program.cs

View workflow job for this annotation

GitHub Actions / Build and Test Pull Requests

The variable 'kex' is declared but never used
return defaultValue;
}
}
Expand Down
36 changes: 17 additions & 19 deletions MobileConfiguration/Repository/IConfigurationRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ namespace MobileConfiguration.Repository
{
using Database;
using Database.Entities;
using Microsoft.EntityFrameworkCore;
using Models;
using Newtonsoft.Json;
using Shared.EntityFramework;
using Shared.Exceptions;
using Microsoft.EntityFrameworkCore;
using Shared.General;
using Shared.Repositories;
using ApplicationCentreConfiguration = Database.Entities.ApplicationCentreConfiguration;

public interface IConfigurationRepository
Expand All @@ -23,24 +25,23 @@ Task UpdateConfiguration(ConfigurationType configurationType,

public class ConfigurationRepository : IConfigurationRepository
{
private readonly Shared.EntityFramework.IDbContextFactory<ConfigurationContext> ContextFactory;

public ConfigurationRepository(Shared.EntityFramework.IDbContextFactory<ConfigurationContext> contextFactory) {
this.ContextFactory = contextFactory;
private readonly IDbContextResolver<ConfigurationContext> Resolver;
private static readonly String ConfigDatabaseName = "ConfigurationDatabase";
public ConfigurationRepository(IDbContextResolver<ConfigurationContext> resolver) {
this.Resolver = resolver;
}
public async Task<MobileConfiguration> GetConfiguration(ConfigurationType configurationType,
String id,
CancellationToken cancellationToken) {
ConfigurationContext context = await this.ContextFactory.GetContext(Guid.NewGuid(), "ConfigurationDatabase",cancellationToken);

Configuration? configuration = await context.Configurations.SingleOrDefaultAsync(c => c.Id == id && c.ConfigType == (Int32)configurationType, cancellationToken:cancellationToken);
using ResolvedDbContext<ConfigurationContext>? resolvedContext = this.Resolver.Resolve(ConfigDatabaseName);
Configuration? configuration = await resolvedContext.Context.Configurations.SingleOrDefaultAsync(c => c.Id == id && c.ConfigType == (Int32)configurationType, cancellationToken:cancellationToken);

if (configuration == null) {
throw new NotFoundException($"No config of type [{configurationType}] found for Id [{id}]");
}

// TODO: create a factory
MobileConfiguration configurationModel = new MobileConfiguration {
MobileConfiguration configurationModel = new() {
ClientId = configuration.ClientId,
ClientSecret = configuration.ClientSecret,
ConfigurationType = (ConfigurationType)configuration.ConfigType,
Expand All @@ -67,14 +68,12 @@ public async Task<MobileConfiguration> GetConfiguration(ConfigurationType config

public async Task<Result> CreateConfiguration(MobileConfiguration mobileConfiguration,
CancellationToken cancellationToken) {
ConfigurationContext context = await this.ContextFactory.GetContext(Guid.NewGuid(), "ConfigurationDatabase", cancellationToken);

Configuration configurationEntity = Factories.Factory.ToEntityConfiguration(mobileConfiguration);

await context.Configurations.AddAsync(configurationEntity,cancellationToken);
using ResolvedDbContext<ConfigurationContext>? resolvedContext = this.Resolver.Resolve(ConfigDatabaseName);
await resolvedContext.Context.Configurations.AddAsync(configurationEntity,cancellationToken);

try {
await context.SaveChangesAsync(cancellationToken);
await resolvedContext.Context.SaveChangesAsync(cancellationToken);
return Result.Success("Configuration created successfully.");
}
catch (Exception ex) {
Expand All @@ -86,9 +85,8 @@ public async Task UpdateConfiguration(ConfigurationType configurationType,
String id,
MobileConfiguration mobileConfiguration,
CancellationToken cancellationToken) {
ConfigurationContext context = await this.ContextFactory.GetContext(Guid.NewGuid(), "ConfigurationDatabase", cancellationToken);

Configuration? configuration = await context.Configurations.SingleOrDefaultAsync(c => c.Id == id && c.ConfigType == (Int32)configurationType, cancellationToken: cancellationToken);
using ResolvedDbContext<ConfigurationContext>? resolvedContext = this.Resolver.Resolve(ConfigDatabaseName);
Configuration? configuration = await resolvedContext.Context.Configurations.SingleOrDefaultAsync(c => c.Id == id && c.ConfigType == (Int32)configurationType, cancellationToken: cancellationToken);

if (configuration == null)
{
Expand All @@ -103,7 +101,7 @@ public async Task UpdateConfiguration(ConfigurationType configurationType,
ConfigType = (Int32)mobileConfiguration.ConfigurationType,
Id = mobileConfiguration.Id,
};
await context.Configurations.AddAsync(configuration, cancellationToken);
await resolvedContext.Context.Configurations.AddAsync(configuration, cancellationToken);
}
else {
configuration.ClientSecret = mobileConfiguration.ClientSecret;
Expand All @@ -114,7 +112,7 @@ public async Task UpdateConfiguration(ConfigurationType configurationType,
configuration.HostAddresses = JsonConvert.SerializeObject(mobileConfiguration.HostAddresses);
}

await context.SaveChangesAsync(cancellationToken);
await resolvedContext.Context.SaveChangesAsync(cancellationToken);
}
}
}
2 changes: 1 addition & 1 deletion MobileConfiguration/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
"InMemoryDatabase": false
},
"ConnectionStrings": {
"ConfigurationDatabase": "server=127.0.0.1;user id=sa;password=sp1ttal;database=ConfigurationHost;Encrypt=false"
"ConfigurationDatabase": "server=127.0.0.1;user id=sa;password=sp1ttal;database=ConfigurationHost-00000000-0000-0000-0000-000000000001;Encrypt=false"
}
}
4 changes: 2 additions & 2 deletions MobileConfiguration/nlog.config
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
<target name="asyncFile" xsi:type="AsyncWrapper">
<target name="logfile" xsi:type="File"
fileName="/home/txnproc/trace/mobileconfiguration.log"
layout="${date:format=dd/MM/yyyy HH\:mm\:ss.ffff} | ${level} | ${callsite:className=true} | ${message} | ${exception:format=type,method:maxInnerExceptionLevel=5:innerFormat=shortType,message,method:InnerExceptionSeparator= | }"
layout="${date:format=dd/MM/yyyy HH\:mm\:ss.ffff} | ${level} |${mdlc:CorrelationId:fallback=NO-ID}| ${callsite:className=true} | ${message} | ${exception:format=type,method:maxInnerExceptionLevel=5:innerFormat=shortType,message,method:InnerExceptionSeparator= | }"
archiveFileName="/home/txnproc/trace/mobileconfiguration.{#####}.log"
archiveAboveSize="104857600"
archiveNumbering="Sequence"
concurrentWrites="true"
maxArchiveFiles="2"/>
<target name="healthlogfile" xsi:type="File"
fileName="/home/txnproc/trace/mobileconfiguration_health.log"
layout="${date:format=dd/MM/yyyy HH\:mm\:ss.ffff} | ${level} | ${callsite:className=true} | ${message} | ${exception:format=type,method:maxInnerExceptionLevel=5:innerFormat=shortType,message,method:InnerExceptionSeparator= | }"
layout="${date:format=dd/MM/yyyy HH\:mm\:ss.ffff} | ${level} |${mdlc:CorrelationId:fallback=NO-ID}| ${callsite:className=true} | ${message} | ${exception:format=type,method:maxInnerExceptionLevel=5:innerFormat=shortType,message,method:InnerExceptionSeparator= | }"
archiveFileName="/home/txnproc/trace/mobileconfiguration_health.{#####}.log"
archiveAboveSize="104857600"
archiveNumbering="Sequence"
Expand Down
Loading