Initial work on getting minimal API to work

This commit is contained in:
Jeff Leung 2024-01-13 16:44:03 -08:00
parent 810993cbf3
commit a44b4f9421
27 changed files with 519 additions and 126 deletions

View File

@ -1,93 +0,0 @@
using AS1024.GeoFeed.Core.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Runtime.CompilerServices;
namespace AS1024.GeoFeed.Core.GeoFeedLocalCache
{
public class GeoFeedCacheService : IHostedService
{
private readonly ILogger<GeoFeedCacheService> logger;
private readonly IGeoFeedProvider feedProvider;
private readonly IHost host;
public GeoFeedCacheService(ILogger<GeoFeedCacheService> logger,
IGeoFeedProvider feedProvider,
IHost host)
{
this.logger = logger;
this.feedProvider = feedProvider;
this.host = host;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_ = StartPerioidicSync(cancellationToken);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public async Task<bool> StartPerioidicSync(CancellationToken Token)
{
await DBContextMigrate();
List<GeoFeedCacheEntry> geoFeedCacheEntry = [];
while (!Token.IsCancellationRequested)
{
logger.LogInformation("Running on disk fallback cache process...");
try
{
using var scope = host.Services.CreateScope();
using var dbContext = scope.ServiceProvider.GetRequiredService<GeoFeedCacheDbContext>();
var results = await feedProvider.GetGeoFeedData();
results.ForEach(x =>
{
geoFeedCacheEntry.Add(new()
{
Prefix = x.Prefix,
GeolocCity = x.GeolocCity,
GeolocCountry = x.GeolocCountry,
GeolocHasLocation = x.GeolocHasLocation,
GeolocPostalCode = x.GeolocPostalCode,
GeolocRegion = x.GeolocRegion
});
});
if (dbContext.GeoFeedCacheEntries.Any())
{
dbContext.GeoFeedCacheEntries.RemoveRange(dbContext.GeoFeedCacheEntries.ToArray());
}
await dbContext.AddRangeAsync(geoFeedCacheEntry, Token);
await dbContext.SaveChangesAsync(Token);
}
catch (Exception ex)
{
logger.LogWarning("On disk cache failed to run. Waiting on 30 minutes before retry...");
}
await Task.Delay(TimeSpan.FromMinutes(30));
}
return false;
}
private async Task DBContextMigrate()
{
using IServiceScope scope = host.Services.CreateScope();
using GeoFeedCacheDbContext? dbContext =
scope.ServiceProvider.GetService<GeoFeedCacheDbContext>();
#pragma warning disable CS8602 // Dereference of a possibly null reference.
if (dbContext.Database.GetPendingMigrations().Any()) {
await dbContext.Database.MigrateAsync();
}
#pragma warning restore CS8602 // Dereference of a possibly null reference.
}
}
}

View File

@ -1,6 +1,6 @@
using Microsoft.EntityFrameworkCore;
namespace AS1024.GeoFeed.Core.GeoFeedLocalCache
namespace AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache
{
public class GeoFeedCacheDbContext : DbContext
{

View File

@ -1,7 +1,7 @@
using AS1024.GeoFeed.Models;
using System.ComponentModel.DataAnnotations;
namespace AS1024.GeoFeed.Core.GeoFeedLocalCache
namespace AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache
{
public class GeoFeedCacheEntry : IPGeoFeed
{

View File

@ -0,0 +1,58 @@
using AS1024.GeoFeed.Core.Interfaces;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Runtime.CompilerServices;
namespace AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache
{
public class GeoFeedCacheService : IHostedService
{
private readonly ILogger<GeoFeedCacheService> logger;
private readonly IGeoFeedProvider feedProvider;
private readonly IHost host;
private readonly IGeoFeedPersistentCacheProvider persistentCacheProvider;
public GeoFeedCacheService(ILogger<GeoFeedCacheService> logger,
IGeoFeedProvider feedProvider,
IHost host,
IGeoFeedPersistentCacheProvider persistentCacheProvider)
{
this.logger = logger;
this.feedProvider = feedProvider;
this.host = host;
this.persistentCacheProvider = persistentCacheProvider;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_ = StartPerioidicSync(cancellationToken);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public async Task<bool> StartPerioidicSync(CancellationToken Token)
{
while (!Token.IsCancellationRequested)
{
try
{
var results = await feedProvider.GetGeoFeedData();
await persistentCacheProvider.CacheGeoFeed(results);
}
catch (Exception)
{
logger.LogWarning("On disk cache failed to run. Waiting on 30 minutes before retry...");
}
await Task.Delay(TimeSpan.FromMinutes(30));
}
return false;
}
}
}

View File

@ -1,7 +1,8 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
namespace AS1024.GeoFeed.Core.GeoFeedLocalCache
namespace AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache
{
public class GeoFeedDesignTimeMigration : IDesignTimeDbContextFactory<GeoFeedCacheDbContext>
{

View File

@ -0,0 +1,72 @@
using AS1024.GeoFeed.Core.Interfaces;
using AS1024.GeoFeed.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using AS1024.GeoFeed.Core.Tools;
namespace AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache
{
public class GeoFeedSqliteCache : IGeoFeedPersistentCacheProvider
{
protected readonly GeoFeedCacheDbContext dbContext;
private readonly IGeoFeedProvider feedProvider;
public GeoFeedSqliteCache(GeoFeedCacheDbContext geoFeedCacheDb,
IHost host,
IGeoFeedProvider provider)
{
dbContext = geoFeedCacheDb;
feedProvider = provider;
}
public string ProviderName => "sqlite";
public async Task<bool> CacheGeoFeed(IList<IPGeoFeed> pGeoFeeds)
{
await DBContextMigrate();
List<GeoFeedCacheEntry> geoFeedCacheEntry = [];
var results = pGeoFeeds.ToList();
results.ForEach(x =>
{
geoFeedCacheEntry.Add(new()
{
Prefix = x.Prefix,
GeolocCity = x.GeolocCity,
GeolocCountry = x.GeolocCountry,
GeolocHasLocation = x.GeolocHasLocation,
GeolocPostalCode = x.GeolocPostalCode,
GeolocRegion = x.GeolocRegion
});
});
if (dbContext.GeoFeedCacheEntries.Any())
{
dbContext.GeoFeedCacheEntries.RemoveRange(dbContext.GeoFeedCacheEntries.ToArray());
}
await dbContext.AddRangeAsync(geoFeedCacheEntry);
await dbContext.SaveChangesAsync();
return true;
}
public string GetGeoFeed()
{
var results =
dbContext.GeoFeedCacheEntries.ToList();
List<IPGeoFeed> cachedData = [];
results.ForEach(cachedData.Add);
return cachedData.ToGeoFeedCsv();
}
private async Task DBContextMigrate()
{
if (dbContext.Database.GetPendingMigrations().Any())
{
await dbContext.Database.MigrateAsync();
}
}
}
}

View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AS1024.GeoFeed.Core\AS1024.GeoFeed.Core.csproj" />
<ProjectReference Include="..\AS1024.GeoFeed.Models\AS1024.GeoFeed.Models.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,15 @@
using Microsoft.EntityFrameworkCore;
namespace AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache
{
public class GeoFeedCacheDbContext : DbContext
{
public GeoFeedCacheDbContext(DbContextOptions options)
: base(options)
{
}
public virtual DbSet<GeoFeedCacheEntry> GeoFeedCacheEntries { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using AS1024.GeoFeed.Models;
using System.ComponentModel.DataAnnotations;
namespace AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache
{
public class GeoFeedCacheEntry : IPGeoFeed
{
[Key]
public int Id { get; set; }
}
}

View File

@ -0,0 +1,17 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
namespace AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache
{
public class GeoFeedDesignTimeMigration : IDesignTimeDbContextFactory<GeoFeedCacheDbContext>
{
public GeoFeedCacheDbContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<GeoFeedCacheDbContext>();
builder.UseSqlite("Data Source=migratedb.db");
return new GeoFeedCacheDbContext(builder.Options);
}
}
}

View File

@ -0,0 +1,72 @@
using AS1024.GeoFeed.Core.Interfaces;
using AS1024.GeoFeed.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using AS1024.GeoFeed.Core.Tools;
namespace AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache
{
public class GeoFeedSqliteCache : IGeoFeedPersistentCacheProvider
{
protected readonly GeoFeedCacheDbContext dbContext;
private readonly IGeoFeedProvider feedProvider;
public GeoFeedSqliteCache(GeoFeedCacheDbContext geoFeedCacheDb,
IHost host,
IGeoFeedProvider provider)
{
dbContext = geoFeedCacheDb;
feedProvider = provider;
}
public string ProviderName => "sqlite";
public async Task<bool> CacheGeoFeed(IList<IPGeoFeed> pGeoFeeds)
{
await DBContextMigrate();
List<GeoFeedCacheEntry> geoFeedCacheEntry = [];
var results = pGeoFeeds.ToList();
results.ForEach(x =>
{
geoFeedCacheEntry.Add(new()
{
Prefix = x.Prefix,
GeolocCity = x.GeolocCity,
GeolocCountry = x.GeolocCountry,
GeolocHasLocation = x.GeolocHasLocation,
GeolocPostalCode = x.GeolocPostalCode,
GeolocRegion = x.GeolocRegion
});
});
if (dbContext.GeoFeedCacheEntries.Any())
{
dbContext.GeoFeedCacheEntries.RemoveRange(dbContext.GeoFeedCacheEntries.ToArray());
}
await dbContext.AddRangeAsync(geoFeedCacheEntry);
await dbContext.SaveChangesAsync();
return true;
}
public string GetGeoFeed()
{
var results =
dbContext.GeoFeedCacheEntries.ToList();
List<IPGeoFeed> cachedData = [];
results.ForEach(cachedData.Add);
return cachedData.ToGeoFeedCsv();
}
private async Task DBContextMigrate()
{
if (dbContext.Database.GetPendingMigrations().Any())
{
await dbContext.Database.MigrateAsync();
}
}
}
}

View File

@ -1,6 +1,6 @@
// <auto-generated />
using System;
using AS1024.GeoFeed.Core.GeoFeedLocalCache;
using AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
@ -8,10 +8,10 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AS1024.GeoFeed.Core.Migrations
namespace AS1024.GeoFeed.Core.SqliteGeoFeedCache.Migrations
{
[DbContext(typeof(GeoFeedCacheDbContext))]
[Migration("20240113204143_InitialMigration")]
[Migration("20240114002908_InitialMigration")]
partial class InitialMigration
{
/// <inheritdoc />
@ -20,7 +20,7 @@ namespace AS1024.GeoFeed.Core.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.0");
modelBuilder.Entity("AS1024.GeoFeed.Core.GeoFeedLocalCache.GeoFeedCacheEntry", b =>
modelBuilder.Entity("AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache.GeoFeedCacheEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()

View File

@ -2,7 +2,7 @@
#nullable disable
namespace AS1024.GeoFeed.Core.Migrations
namespace AS1024.GeoFeed.Core.SqliteGeoFeedCache.Migrations
{
/// <inheritdoc />
public partial class InitialMigration : Migration

View File

@ -1,13 +1,13 @@
// <auto-generated />
using System;
using AS1024.GeoFeed.Core.GeoFeedLocalCache;
using AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace AS1024.GeoFeed.Core.Migrations
namespace AS1024.GeoFeed.Core.SqliteGeoFeedCache.Migrations
{
[DbContext(typeof(GeoFeedCacheDbContext))]
partial class GeoFeedCacheDbContextModelSnapshot : ModelSnapshot
@ -17,7 +17,7 @@ namespace AS1024.GeoFeed.Core.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.0");
modelBuilder.Entity("AS1024.GeoFeed.Core.GeoFeedLocalCache.GeoFeedCacheEntry", b =>
modelBuilder.Entity("AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache.GeoFeedCacheEntry", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()

View File

@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />

View File

@ -0,0 +1,58 @@
using AS1024.GeoFeed.Core.Interfaces;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace AS1024.GeoFeed.Core.CacheService
{
public class GeoFeedCacheService : IHostedService
{
private readonly ILogger<GeoFeedCacheService> logger;
private readonly IGeoFeedProvider feedProvider;
private readonly IHost host;
public GeoFeedCacheService(ILogger<GeoFeedCacheService> logger,
IGeoFeedProvider feedProvider,
IHost host)
{
this.logger = logger;
this.feedProvider = feedProvider;
this.host = host;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_ = StartPerioidicSync(cancellationToken);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public async Task<bool> StartPerioidicSync(CancellationToken Token)
{
while (!Token.IsCancellationRequested)
{
try
{
var scope = host.Services.CreateScope();
var persistentCacheProvider =
scope.ServiceProvider.GetRequiredService<IGeoFeedPersistentCacheProvider>();
var results = await feedProvider.GetGeoFeedData();
await persistentCacheProvider.CacheGeoFeed(results);
}
catch (Exception)
{
logger.LogWarning("On disk cache failed to run. Waiting on 30 minutes before retry...");
}
await Task.Delay(TimeSpan.FromMinutes(30));
}
return false;
}
}
}

View File

@ -0,0 +1,55 @@
using AS1024.GeoFeed.Core.Interfaces;
using AS1024.GeoFeed.Models;
using AS1024.GeoFeed.Core.Tools;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace AS1024.GeoFeed.Core.CacheService
{
public class GeoFeedLocalFileCache : IGeoFeedPersistentCacheProvider
{
private readonly IConfiguration configuration;
private readonly ILogger<GeoFeedLocalFileCache> logger;
public GeoFeedLocalFileCache(IConfiguration _configuration,
ILogger<GeoFeedLocalFileCache> logger)
{
configuration = _configuration;
this.logger = logger;
}
string IGeoFeedPersistentCacheProvider.ProviderName => "file";
Task<bool> IGeoFeedPersistentCacheProvider.CacheGeoFeed(IList<IPGeoFeed> pGeoFeeds)
{
string? tempPath = GetTempPath();
logger.LogInformation($"Writing geofeed data to: {tempPath}");
File.WriteAllText(tempPath, pGeoFeeds.ToList().
ToGeoFeedCsv());
return Task.FromResult(true);
}
private string GetTempPath()
{
string? tempPath = Path.Combine(Path.GetTempPath(), "geoFeedCache.csv");
logger.LogInformation($"Getting GeoFeed data from: {tempPath}");
if (!string.IsNullOrEmpty(configuration["TempCache"]))
tempPath = configuration["TempCache"];
return tempPath;
}
string IGeoFeedPersistentCacheProvider.GetGeoFeed()
{
return File.ReadAllText(GetTempPath());
}
}
}

View File

@ -1,4 +1,5 @@
using AS1024.GeoFeed.Core.Interfaces;
using AS1024.GeoFeed.Models;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@ -40,7 +41,7 @@ namespace AS1024.GeoFeed.Core.GeoFeedPreloader
private async Task StartPreLoad()
{
logger.LogInformation("Preloading GeoFeed data in memory...");
List<Models.IPGeoFeed> feed = await provider.GetGeoFeedData();
List<IPGeoFeed> feed = await provider.GetGeoFeedData();
MemoryCacheEntryOptions cacheEntryOptions = new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(45));
memoryCache.Set(GeoFeedCacheKey, feed, cacheEntryOptions);
}

View File

@ -0,0 +1,31 @@
using AS1024.GeoFeed.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AS1024.GeoFeed.Core.Interfaces
{
/// <summary>
/// Represents a persistent cache GeoFeed provider
/// </summary>
public interface IGeoFeedPersistentCacheProvider
{
/// <summary>
/// Name of the provider
/// </summary>
public string ProviderName { get; }
/// <summary>
/// Returns the GeoFeed
/// </summary>
/// <returns>String of the CSV geofeed</returns>
public string GetGeoFeed();
/// <summary>
/// Stores the GeoFeed in the cache backend
/// </summary>
/// <param name="pGeoFeeds">GeoFeed retrieved from the backend</param>
/// <returns></returns>
public Task<bool> CacheGeoFeed(IList<IPGeoFeed> pGeoFeeds);
}
}

View File

@ -13,4 +13,8 @@
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AS1024.GeoFeed.Core\AS1024.GeoFeed.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,31 @@
using AS1024.GeoFeed.Core.GeoFeedProviders;
using AS1024.GeoFeed.Core.Interfaces;
using AS1024.GeoFeed.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization.Metadata;
using System.Threading.Tasks;
namespace AS1024.GeoFeed.MinimalAPI
{
internal class NetboxAoTGeoFeedProvider : NetBoxGeoFeedProvider, IGeoFeedProvider
{
private readonly JsonSerializerOptions appJsonSerializer;
public NetboxAoTGeoFeedProvider(IConfiguration configuration,
ILogger<NetBoxGeoFeedProvider> logger,
IHttpClientFactory httpClientFactory)
: base(configuration, logger, httpClientFactory)
{
}
protected override NetboxData? DeserializeJsonData(string stringResult)
{
return JsonSerializer.Deserialize(stringResult, AppJsonSerializerContext.Default.NetboxData);
}
}
}

View File

@ -1,3 +1,9 @@
using AS1024.GeoFeed.Core.GeoFeedProviders;
using AS1024.GeoFeed.Core.Interfaces;
using AS1024.GeoFeed.Core.Tools;
using AS1024.GeoFeed.Models;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json.Serialization;
namespace AS1024.GeoFeed.MinimalAPI
@ -7,12 +13,39 @@ namespace AS1024.GeoFeed.MinimalAPI
public static void Main(string[] args)
{
var builder = WebApplication.CreateSlimBuilder(args);
builder.Services.AddTransient<IGeoFeedProvider, NetboxAoTGeoFeedProvider>();
builder.Services.AddMemoryCache();
builder.Services.AddLogging();
builder.Services.AddHttpClient();
builder.Services.ConfigureHttpJsonOptions(options => {
options.SerializerOptions.TypeInfoResolverChain.Insert(0, AppJsonSerializerContext.Default);
});
var app = builder.Build();
var geoFeed = app.MapGroup("/geofeed.csv");
var geoFeed = app.Map("/geofeed.csv", async (IGeoFeedProvider provider, ILogger<Program> logger) => {
try
{
var results =
await provider.GetGeoFeedData();
return results.ToGeoFeedCsv();
}
catch (Exception ex)
{
logger.LogError($"Error: {ex}");
}
return "";
});
app.Run();
}
}
[JsonSerializable(typeof(NetboxData))]
[JsonSerializable(typeof(Result))]
[JsonSerializable(typeof(CustomFields))]
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower)]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}
}

View File

@ -14,7 +14,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AS1024.GeoFeed.Core", "AS10
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AS1024.GeoFeed.MinimalAPI", "AS1024.GeoFeed.MinimalAPI\AS1024.GeoFeed.MinimalAPI.csproj", "{36F2958C-8D0E-463B-9BF3-D6E55E6FC0B8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AS1024.GeoFeed.Core.GeoFeedLocalCache", "AS1024.GeoFeed.Core.GeoFeedLocalCache\AS1024.GeoFeed.Core.GeoFeedLocalCache.csproj", "{C474F55D-AE8E-4DF3-A241-FB017551C74A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AS1024.GeoFeed.Core.SqliteGeoFeedCache", "AS1024.GeoFeed.Core.SqliteGeoFeedCache\AS1024.GeoFeed.Core.SqliteGeoFeedCache.csproj", "{3459BB31-FA7A-44D1-872D-C5338ACFBF80}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -38,10 +38,10 @@ Global
{36F2958C-8D0E-463B-9BF3-D6E55E6FC0B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{36F2958C-8D0E-463B-9BF3-D6E55E6FC0B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{36F2958C-8D0E-463B-9BF3-D6E55E6FC0B8}.Release|Any CPU.Build.0 = Release|Any CPU
{C474F55D-AE8E-4DF3-A241-FB017551C74A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C474F55D-AE8E-4DF3-A241-FB017551C74A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C474F55D-AE8E-4DF3-A241-FB017551C74A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C474F55D-AE8E-4DF3-A241-FB017551C74A}.Release|Any CPU.Build.0 = Release|Any CPU
{3459BB31-FA7A-44D1-872D-C5338ACFBF80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3459BB31-FA7A-44D1-872D-C5338ACFBF80}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3459BB31-FA7A-44D1-872D-C5338ACFBF80}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3459BB31-FA7A-44D1-872D-C5338ACFBF80}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -22,7 +22,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AS1024.GeoFeed.Core.GeoFeedLocalCache\AS1024.GeoFeed.Core.GeoFeedLocalCache.csproj" />
<ProjectReference Include="..\AS1024.GeoFeed.Core.SqliteGeoFeedCache\AS1024.GeoFeed.Core.SqliteGeoFeedCache.csproj" />
<ProjectReference Include="..\AS1024.GeoFeed.Core\AS1024.GeoFeed.Core.csproj" />
<ProjectReference Include="..\AS1024.GeoFeed.Models\AS1024.GeoFeed.Models.csproj" />
</ItemGroup>

View File

@ -3,7 +3,6 @@ using AS1024.GeoFeed.Core.Interfaces;
using Microsoft.Extensions.Caching.Memory;
using AS1024.GeoFeed.Models;
using System.Text;
using AS1024.GeoFeed.Core.GeoFeedLocalCache;
using AS1024.GeoFeed.Core.Tools;
namespace AS1024.GeoFeed.Controllers
@ -18,16 +17,16 @@ namespace AS1024.GeoFeed.Controllers
private readonly IMemoryCache memoryCache;
private readonly IWebHostEnvironment environment;
private readonly ILogger<GeofeedController> logger;
private readonly GeoFeedCacheDbContext dbContext;
private readonly IGeoFeedPersistentCacheProvider geoFeedPersistentCache;
private const string GeoFeedCacheKey = "GeoFeedData";
public GeofeedController(IGeoFeedProvider builder,
IMemoryCache memoryCache,
IWebHostEnvironment environment,
ILogger<GeofeedController> logger,
GeoFeedCacheDbContext dbContext) {
IGeoFeedPersistentCacheProvider geoFeedPersistentCache) {
this.logger = logger;
this.dbContext = dbContext;
this.geoFeedPersistentCache = geoFeedPersistentCache;
this.builder = builder;
this.memoryCache = memoryCache;
this.environment = environment;
@ -54,10 +53,7 @@ namespace AS1024.GeoFeed.Controllers
} catch (HttpRequestException ex)
{
logger.LogWarning($"Temporary failure of retrieving GeoData from upstream. {ex}");
var results =
dbContext.GeoFeedCacheEntries.ToList();
List<IPGeoFeed> cachedData = [];
results.ForEach(cachedData.Add);
var cachedData = geoFeedPersistentCache.GetGeoFeed();
return ReturnFile(cachedData);
}
@ -73,6 +69,12 @@ namespace AS1024.GeoFeed.Controllers
private IActionResult ReturnFile(List<IPGeoFeed>? feed)
{
string csvContent = feed.ToGeoFeedCsv(); // Assuming ToGeoFeedCsv() returns a string in CSV format.
return ReturnFile(csvContent);
}
[NonAction]
private IActionResult ReturnFile(string csvContent)
{
byte[] contentBytes = Encoding.UTF8.GetBytes(csvContent);
string contentType = "text/csv";

View File

@ -1,8 +1,9 @@
using AS1024.GeoFeed.Core.Interfaces;
using AS1024.GeoFeed.Core.GeoFeedPreloader;
using AS1024.GeoFeed.Core.GeoFeedLocalCache;
using AS1024.GeoFeed.Core.GeoFeedProviders;
using Microsoft.EntityFrameworkCore;
using AS1024.GeoFeed.Core.GeoFeedSqliteLocalCache;
using AS1024.GeoFeed.Core.CacheService;
namespace AS1024.GeoFeed
{
@ -14,11 +15,13 @@ namespace AS1024.GeoFeed
builder.Services.AddHostedService<PreLoadGeoFeed>();
builder.Services.AddTransient<IGeoFeedProvider, NetBoxGeoFeedProvider>();
builder.Services.AddDbContext<GeoFeedCacheDbContext>(
options =>
{
options.UseSqlite(builder.Configuration.GetConnectionString("LocalFeedCache"));
});
builder.Services.AddScoped<IGeoFeedPersistentCacheProvider, GeoFeedSqliteCache>();
builder.Services.AddHostedService<GeoFeedCacheService>();
builder.Services.AddDbContext<GeoFeedCacheDbContext>(options =>
{
options.UseSqlite(builder.Configuration.GetConnectionString("LocalFeedCache"));
});
builder.Services.AddHttpClient();
builder.Services.AddMemoryCache();
// Add services to the container.