Last active
April 26, 2021 14:05
-
-
Save mr5z/e7983ed550b3107857f89ca4e6bafc84 to your computer and use it in GitHub Desktop.
Scheduled closing of config file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class Configuration : IConfiguration | |
{ | |
private readonly string assemblyResourceFile; | |
private AutoDisposeJsonDocument? smartJsonDocument; | |
public Configuration(string assemblyResourceFile) | |
{ | |
this.assemblyResourceFile = assemblyResourceFile; | |
} | |
public static IConfiguration FromCurrentAssembly(string assemblyResourceFile) | |
{ | |
var assemblyName = typeof(Configuration).Assembly.GetName().Name; | |
return new Configuration($"{assemblyName}.{assemblyResourceFile}"); | |
} | |
private T? GetValueImpl<T>(string path, JsonDocument jsonDocument, JsonSerializerOptions? options) | |
{ | |
var root = jsonDocument.RootElement; | |
var jsonPath = JsonPath.Parse(path); | |
var pathResult = jsonPath.Evaluate(root); | |
if (pathResult.Error != null) | |
throw new InvalidOperationException(pathResult.Error); | |
var matches = pathResult.Matches!; | |
var first = matches.First(); | |
var value = typeof(T) == typeof(string) ? | |
$"\"{first.Value}\"" : | |
$"{first.Value}"; | |
return JsonSerializer.Deserialize<T?>(value, options); | |
} | |
public T? GetValue<T>(string path, JsonSerializerOptions? options) | |
{ | |
smartJsonDocument ??= new AutoDisposeJsonDocument(assemblyResourceFile); | |
var jsonDocument = smartJsonDocument.ParseJsonDocument(); | |
return GetValueImpl<T>(path, jsonDocument, options); | |
} | |
public async Task<T?> GetValueAsync<T>( | |
string path, JsonSerializerOptions? options, CancellationToken cancellationToken) | |
{ | |
smartJsonDocument ??= new AutoDisposeJsonDocument(assemblyResourceFile); | |
var jsonDocument = await smartJsonDocument.ParseJsonDocumentAsync(cancellationToken); | |
return GetValueImpl<T>(path, jsonDocument, options); | |
} | |
private protected class AutoDisposeJsonDocument | |
{ | |
private readonly string jsonFile; | |
private Stream? jsonStream; | |
private JsonDocument? jsonDocument; | |
public AutoDisposeJsonDocument(string jsonFile) | |
{ | |
this.jsonFile = jsonFile; | |
} | |
public JsonDocument ParseJsonDocument() | |
{ | |
if (jsonDocument == null) | |
{ | |
var stream = GetAutoDisposeStream(); | |
jsonDocument = JsonDocument.Parse(stream); | |
} | |
return jsonDocument; | |
} | |
public async Task<JsonDocument> ParseJsonDocumentAsync( | |
CancellationToken cancellationToken) | |
{ | |
if (jsonDocument == null) | |
{ | |
var stream = GetAutoDisposeStream(); | |
jsonDocument = await JsonDocument.ParseAsync(stream, cancellationToken: cancellationToken); | |
} | |
return jsonDocument; | |
} | |
private Stream GetAutoDisposeStream() | |
{ | |
if (jsonStream == null) | |
{ | |
jsonStream = GetStream(); | |
ScheduleDisposeResourceStreams(); | |
} | |
return jsonStream; | |
} | |
private Stream GetStream() | |
{ | |
var assembly = Assembly.GetExecutingAssembly(); | |
var resourceNames = assembly.GetManifestResourceNames(); | |
if (!resourceNames.Contains(jsonFile)) | |
throw new FileNotFoundException($"Embedded resource not found: '{jsonFile}'"); | |
return assembly.GetManifestResourceStream(jsonFile); | |
} | |
private void ScheduleDisposeResourceStreams() | |
{ | |
_ = Task.Factory.StartNew(async () => | |
{ | |
await Task.Delay(TimeSpan.FromMinutes(1)); | |
// in the same thread so no lock needed | |
jsonStream?.Dispose(); | |
jsonDocument?.Dispose(); | |
jsonStream = null; | |
jsonDocument = null; | |
}, default, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment