diff --git a/README.md b/README.md index 9686641..b257023 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The `CodeCargo.Nats.HybridCacheExtensions` package provides an extension method ```bash dotnet add package CodeCargo.Nats.HybridCacheExtensions -dotnet add package NATS.Net +dotnet add package NATS.Extensions.Microsoft.DependencyInjection ``` ### Example @@ -38,16 +38,19 @@ using CodeCargo.Nats.HybridCacheExtensions; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using NATS.Client.Core; -using NATS.Client.Hosting; using NATS.Client.KeyValueStore; +using NATS.Extensions.Microsoft.DependencyInjection; using NATS.Net; +// Set the NATS URL, this normally comes from configuration const string natsUrl = "nats://localhost:4222"; + +// Create a host builder for a Console application +// For a Web Application you can use WebApplication.CreateBuilder(args) var builder = Host.CreateDefaultBuilder(args); builder.ConfigureServices(services => { - services.AddNats(configureOpts: options => options with { Url = natsUrl }); - + services.AddNatsClient(natsBuilder => natsBuilder.ConfigureOptions(opts => opts with { Url = natsUrl })); services.AddNatsHybridCache(options => { options.BucketName = "cache"; @@ -55,6 +58,8 @@ builder.ConfigureServices(services => }); var host = builder.Build(); + +// Ensure that the KV Store is created var natsConnection = host.Services.GetRequiredService(); var kvContext = natsConnection.CreateKeyValueStoreContext(); await kvContext.CreateOrUpdateStoreAsync(new NatsKVConfig("cache") @@ -62,6 +67,7 @@ await kvContext.CreateOrUpdateStoreAsync(new NatsKVConfig("cache") LimitMarkerTTL = TimeSpan.FromSeconds(1) }); +// Start the host await host.RunAsync(); ``` @@ -71,7 +77,7 @@ await host.RunAsync(); ```bash dotnet add package CodeCargo.Nats.DistributedCache -dotnet add package NATS.Net +dotnet add package NATS.Extensions.Microsoft.DependencyInjection ``` ### Example @@ -81,16 +87,19 @@ using CodeCargo.Nats.DistributedCache; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using NATS.Client.Core; -using NATS.Client.Hosting; using NATS.Client.KeyValueStore; +using NATS.Extensions.Microsoft.DependencyInjection; using NATS.Net; +// Set the NATS URL, this normally comes from configuration const string natsUrl = "nats://localhost:4222"; + +// Create a host builder for a Console application +// For a Web Application you can use WebApplication.CreateBuilder(args) var builder = Host.CreateDefaultBuilder(args); builder.ConfigureServices(services => { - services.AddNats(configureOpts: options => options with { Url = natsUrl }); - + services.AddNatsClient(natsBuilder => natsBuilder.ConfigureOptions(opts => opts with { Url = natsUrl })); services.AddNatsDistributedCache(options => { options.BucketName = "cache"; @@ -98,13 +107,13 @@ builder.ConfigureServices(services => }); var host = builder.Build(); + +// Ensure that the KV Store is created var natsConnection = host.Services.GetRequiredService(); var kvContext = natsConnection.CreateKeyValueStoreContext(); -await kvContext.CreateOrUpdateStoreAsync(new NatsKVConfig("cache") -{ - LimitMarkerTTL = TimeSpan.FromSeconds(1) -}); +await kvContext.CreateOrUpdateStoreAsync(new NatsKVConfig("cache") { LimitMarkerTTL = TimeSpan.FromSeconds(1) }); +// Start the host await host.RunAsync(); ``` diff --git a/util/ReadmeExample/Abbreviated.cs b/util/ReadmeExample/DistributedCache.Example.cs similarity index 58% rename from util/ReadmeExample/Abbreviated.cs rename to util/ReadmeExample/DistributedCache.Example.cs index 8c6132f..2f5cb88 100644 --- a/util/ReadmeExample/Abbreviated.cs +++ b/util/ReadmeExample/DistributedCache.Example.cs @@ -2,13 +2,12 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using NATS.Client.Core; -using NATS.Client.Hosting; using NATS.Client.KeyValueStore; +using NATS.Extensions.Microsoft.DependencyInjection; using NATS.Net; -// The abbreviated example put into the README.md -// Based on Program.cs -public static class Abbreviated +// Example used in the README.md "Use `IDistributedCache` Directly" section +public static class DistributedCacheExample { public static async Task Run(string[] args) { @@ -18,39 +17,21 @@ public static async Task Run(string[] args) // Create a host builder for a Console application // For a Web Application you can use WebApplication.CreateBuilder(args) var builder = Host.CreateDefaultBuilder(args); - - // Add services to the container builder.ConfigureServices(services => { - // Add NATS client - services.AddNats(configureOpts: options => options with { Url = natsUrl }); - - // Add a NATS distributed cache + services.AddNatsClient(natsBuilder => natsBuilder.ConfigureOptions(opts => opts with { Url = natsUrl })); services.AddNatsDistributedCache(options => { options.BucketName = "cache"; }); - - // (Optional) Add HybridCache - var hybridCacheServices = services.AddHybridCache(); - - // (Optional) Use NATS Serializer for HybridCache - hybridCacheServices.AddSerializerFactory( - NatsOpts.Default.SerializerRegistry.ToHybridCacheSerializerFactory()); - - // Add other services as needed }); - // Build the host var host = builder.Build(); // Ensure that the KV Store is created var natsConnection = host.Services.GetRequiredService(); var kvContext = natsConnection.CreateKeyValueStoreContext(); - await kvContext.CreateOrUpdateStoreAsync(new NatsKVConfig("cache") - { - LimitMarkerTTL = TimeSpan.FromSeconds(1) - }); + await kvContext.CreateOrUpdateStoreAsync(new NatsKVConfig("cache") { LimitMarkerTTL = TimeSpan.FromSeconds(1) }); // Start the host await host.RunAsync(); diff --git a/util/ReadmeExample/DistributedCache.cs b/util/ReadmeExample/DistributedCache.cs index ea1f1b1..e5d7aa3 100644 --- a/util/ReadmeExample/DistributedCache.cs +++ b/util/ReadmeExample/DistributedCache.cs @@ -6,8 +6,8 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NATS.Client.Core; -using NATS.Client.Hosting; using NATS.Client.KeyValueStore; +using NATS.Extensions.Microsoft.DependencyInjection; using NATS.Net; namespace CodeCargo.ReadmeExample; @@ -36,10 +36,12 @@ public static async Task RunAsync(string[] args) throw new InvalidOperationException("Cannot find connection string for NATS"); } + // Create a host builder for a Console application + // For a Web Application you can use WebApplication.CreateBuilder(args) var builder = Host.CreateDefaultBuilder(args); builder.ConfigureServices(services => { - services.AddNats(configureOpts: options => options with { Url = natsConnectionString }); + services.AddNatsClient(natsBuilder => natsBuilder.ConfigureOptions(opts => opts with { Url = natsConnectionString })); services.AddNatsDistributedCache(options => { options.BucketName = "cache"; @@ -51,6 +53,7 @@ public static async Task RunAsync(string[] args) var host = builder.Build(); var lifetime = host.Services.GetRequiredService(); + // Ensure that the KV Store is created Console.WriteLine("Creating KV store..."); var natsConnection = host.Services.GetRequiredService(); var kvContext = natsConnection.CreateKeyValueStoreContext(); @@ -58,6 +61,7 @@ await kvContext.CreateOrUpdateStoreAsync( new NatsKVConfig("cache") { LimitMarkerTTL = TimeSpan.FromSeconds(1) }, startupCts.Token); Console.WriteLine("KV store created"); + // Start the host Console.WriteLine("Starting app..."); using var appCts = new CancellationTokenSource(); var appTask = Task.Run(async () => @@ -117,34 +121,26 @@ private static async Task WaitForApplicationStartAsync(IHostApplicationLifetime } } -public class DistributedCacheService +public class DistributedCacheService(IDistributedCache cache, ILogger logger) { - private readonly IDistributedCache _cache; - private readonly ILogger _logger; - - public DistributedCacheService(IDistributedCache cache, ILogger logger) - { - _cache = cache; - _logger = logger; - } - public async Task Run() { - _logger.LogInformation("------------------------------------------"); - _logger.LogInformation("DistributedCache example"); + logger.LogInformation("------------------------------------------"); + logger.LogInformation("DistributedCache example"); const string cacheKey = "distributed-cache-greeting"; const string value = "Hello from NATS Distributed Cache!"; - await _cache.SetStringAsync( + await cache.SetStringAsync( cacheKey, value, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(1) }); - _logger.LogInformation("Set value in cache: {Value}", value); + logger.LogInformation("Set value in cache: {Value}", value); - var retrievedValue = await _cache.GetStringAsync(cacheKey); - _logger.LogInformation("Retrieved value from cache: {Value}", retrievedValue); + var retrievedValue = await cache.GetStringAsync(cacheKey); + logger.LogInformation("Retrieved value from cache: {Value}", retrievedValue); - await _cache.RemoveAsync(cacheKey); - _logger.LogInformation("Removed value from cache"); + await cache.RemoveAsync(cacheKey); + logger.LogInformation("Removed value from cache"); + logger.LogInformation("------------------------------------------"); } } diff --git a/util/ReadmeExample/HybridCache.Example.cs b/util/ReadmeExample/HybridCache.Example.cs new file mode 100644 index 0000000..9a5e025 --- /dev/null +++ b/util/ReadmeExample/HybridCache.Example.cs @@ -0,0 +1,39 @@ +using CodeCargo.Nats.HybridCacheExtensions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using NATS.Client.Core; +using NATS.Client.KeyValueStore; +using NATS.Extensions.Microsoft.DependencyInjection; +using NATS.Net; + +// Example used in the README.md "Use with `HybridCache`" section +public static class HybridCacheExample +{ + public static async Task Run(string[] args) + { + // Set the NATS URL, this normally comes from configuration + const string natsUrl = "nats://localhost:4222"; + + // Create a host builder for a Console application + // For a Web Application you can use WebApplication.CreateBuilder(args) + var builder = Host.CreateDefaultBuilder(args); + builder.ConfigureServices(services => + { + services.AddNatsClient(natsBuilder => natsBuilder.ConfigureOptions(opts => opts with { Url = natsUrl })); + services.AddNatsHybridCache(options => + { + options.BucketName = "cache"; + }); + }); + + var host = builder.Build(); + + // Ensure that the KV Store is created + var natsConnection = host.Services.GetRequiredService(); + var kvContext = natsConnection.CreateKeyValueStoreContext(); + await kvContext.CreateOrUpdateStoreAsync(new NatsKVConfig("cache") { LimitMarkerTTL = TimeSpan.FromSeconds(1) }); + + // Start the host + await host.RunAsync(); + } +} diff --git a/util/ReadmeExample/HybridCache.cs b/util/ReadmeExample/HybridCache.cs index 01c13f6..4ab9c35 100644 --- a/util/ReadmeExample/HybridCache.cs +++ b/util/ReadmeExample/HybridCache.cs @@ -6,8 +6,8 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using NATS.Client.Core; -using NATS.Client.Hosting; using NATS.Client.KeyValueStore; +using NATS.Extensions.Microsoft.DependencyInjection; using NATS.Net; namespace CodeCargo.ReadmeExample; @@ -36,10 +36,12 @@ public static async Task RunAsync(string[] args) throw new InvalidOperationException("Cannot find connection string for NATS"); } + // Create a host builder for a Console application + // For a Web Application you can use WebApplication.CreateBuilder(args) var builder = Host.CreateDefaultBuilder(args); builder.ConfigureServices(services => { - services.AddNats(configureOpts: options => options with { Url = natsConnectionString }); + services.AddNatsClient(natsBuilder => natsBuilder.ConfigureOptions(opts => opts with { Url = natsConnectionString })); services.AddNatsHybridCache(options => { options.BucketName = "cache"; @@ -51,6 +53,7 @@ public static async Task RunAsync(string[] args) var host = builder.Build(); var lifetime = host.Services.GetRequiredService(); + // Ensure that the KV Store is created Console.WriteLine("Creating KV store..."); var natsConnection = host.Services.GetRequiredService(); var kvContext = natsConnection.CreateKeyValueStoreContext(); @@ -58,6 +61,7 @@ await kvContext.CreateOrUpdateStoreAsync( new NatsKVConfig("cache") { LimitMarkerTTL = TimeSpan.FromSeconds(1) }, startupCts.Token); Console.WriteLine("KV store created"); + // Start the host Console.WriteLine("Starting app..."); using var appCts = new CancellationTokenSource(); var appTask = Task.Run(async () => @@ -117,31 +121,25 @@ private static async Task WaitForApplicationStartAsync(IHostApplicationLifetime } } -public class HybridCacheService +public class HybridCacheService(HybridCache cache, ILogger logger) { - private readonly HybridCache _cache; - private readonly ILogger _logger; - - public HybridCacheService(HybridCache cache, ILogger logger) - { - _cache = cache; - _logger = logger; - } - public async Task Run() { - _logger.LogInformation("------------------------------------------"); - _logger.LogInformation("HybridCache example"); + logger.LogInformation("------------------------------------------"); + logger.LogInformation("HybridCache example"); const string key = "hybrid-cache-greeting"; - var result = await _cache.GetOrCreateAsync( + var result = await cache.GetOrCreateAsync( key, - _ => ValueTask.FromResult("Hello from NATS Hybrid Cache!"), + _ => ValueTask.FromResult(new Person("John Doe", 30)), new HybridCacheEntryOptions { Expiration = TimeSpan.FromMinutes(1) }); - _logger.LogInformation("Got/created value from cache: {Result}", result); + logger.LogInformation("Got/created value from cache: {Result}", result); - await _cache.RemoveAsync(key); - _logger.LogInformation("Removed value from cache"); + await cache.RemoveAsync(key); + logger.LogInformation("Removed value from cache"); + logger.LogInformation("------------------------------------------"); } + + private record Person(string Name, int Age); } diff --git a/util/ReadmeExample/ReadmeExample.csproj b/util/ReadmeExample/ReadmeExample.csproj index 5c9ea40..55876d9 100644 --- a/util/ReadmeExample/ReadmeExample.csproj +++ b/util/ReadmeExample/ReadmeExample.csproj @@ -8,7 +8,7 @@ - + diff --git a/util/ReadmeExample/packages.linux-x64.lock.json b/util/ReadmeExample/packages.linux-x64.lock.json index ece7a0c..db5c30e 100644 --- a/util/ReadmeExample/packages.linux-x64.lock.json +++ b/util/ReadmeExample/packages.linux-x64.lock.json @@ -36,20 +36,14 @@ "System.IO.Hashing": "9.0.3" } }, - "NATS.Net": { + "NATS.Extensions.Microsoft.DependencyInjection": { "type": "Direct", "requested": "[2.6.0, )", "resolved": "2.6.0", - "contentHash": "rE1jwq7HMLMfOscaC5dOh1VSOrkA4a2EeKnehaFuiygo3VC2g9ONae5KsNSEdioOoHlRq6xDG9Wu4qNa+1tuCQ==", + "contentHash": "riwSWcfutHlt3gQQU3wgImjgNNLnS6y/5G5Rj7XEGNnoNCEJvtdVHQyaICHg05ehexLiDf4idJrR/KVTldWD2w==", "dependencies": { - "NATS.Client.Core": "2.6.0", - "NATS.Client.Hosting": "2.6.0", - "NATS.Client.JetStream": "2.6.0", - "NATS.Client.KeyValueStore": "2.6.0", - "NATS.Client.ObjectStore": "2.6.0", - "NATS.Client.Serializers.Json": "2.6.0", - "NATS.Client.Services": "2.6.0", - "NATS.Client.Simplified": "2.6.0" + "Microsoft.Extensions.Hosting.Abstractions": "8.0.0", + "NATS.Net": "2.6.0" } }, "StyleCop.Analyzers": { @@ -837,6 +831,21 @@ "NATS.Client.Serializers.Json": "2.6.0" } }, + "NATS.Net": { + "type": "Transitive", + "resolved": "2.6.0", + "contentHash": "rE1jwq7HMLMfOscaC5dOh1VSOrkA4a2EeKnehaFuiygo3VC2g9ONae5KsNSEdioOoHlRq6xDG9Wu4qNa+1tuCQ==", + "dependencies": { + "NATS.Client.Core": "2.6.0", + "NATS.Client.Hosting": "2.6.0", + "NATS.Client.JetStream": "2.6.0", + "NATS.Client.KeyValueStore": "2.6.0", + "NATS.Client.ObjectStore": "2.6.0", + "NATS.Client.Serializers.Json": "2.6.0", + "NATS.Client.Services": "2.6.0", + "NATS.Client.Simplified": "2.6.0" + } + }, "Nerdbank.Streams": { "type": "Transitive", "resolved": "2.11.90", diff --git a/util/ReadmeExample/packages.osx-arm64.lock.json b/util/ReadmeExample/packages.osx-arm64.lock.json index fac3687..89f5270 100644 --- a/util/ReadmeExample/packages.osx-arm64.lock.json +++ b/util/ReadmeExample/packages.osx-arm64.lock.json @@ -36,20 +36,14 @@ "System.IO.Hashing": "9.0.3" } }, - "NATS.Net": { + "NATS.Extensions.Microsoft.DependencyInjection": { "type": "Direct", "requested": "[2.6.0, )", "resolved": "2.6.0", - "contentHash": "rE1jwq7HMLMfOscaC5dOh1VSOrkA4a2EeKnehaFuiygo3VC2g9ONae5KsNSEdioOoHlRq6xDG9Wu4qNa+1tuCQ==", + "contentHash": "riwSWcfutHlt3gQQU3wgImjgNNLnS6y/5G5Rj7XEGNnoNCEJvtdVHQyaICHg05ehexLiDf4idJrR/KVTldWD2w==", "dependencies": { - "NATS.Client.Core": "2.6.0", - "NATS.Client.Hosting": "2.6.0", - "NATS.Client.JetStream": "2.6.0", - "NATS.Client.KeyValueStore": "2.6.0", - "NATS.Client.ObjectStore": "2.6.0", - "NATS.Client.Serializers.Json": "2.6.0", - "NATS.Client.Services": "2.6.0", - "NATS.Client.Simplified": "2.6.0" + "Microsoft.Extensions.Hosting.Abstractions": "8.0.0", + "NATS.Net": "2.6.0" } }, "StyleCop.Analyzers": { @@ -837,6 +831,21 @@ "NATS.Client.Serializers.Json": "2.6.0" } }, + "NATS.Net": { + "type": "Transitive", + "resolved": "2.6.0", + "contentHash": "rE1jwq7HMLMfOscaC5dOh1VSOrkA4a2EeKnehaFuiygo3VC2g9ONae5KsNSEdioOoHlRq6xDG9Wu4qNa+1tuCQ==", + "dependencies": { + "NATS.Client.Core": "2.6.0", + "NATS.Client.Hosting": "2.6.0", + "NATS.Client.JetStream": "2.6.0", + "NATS.Client.KeyValueStore": "2.6.0", + "NATS.Client.ObjectStore": "2.6.0", + "NATS.Client.Serializers.Json": "2.6.0", + "NATS.Client.Services": "2.6.0", + "NATS.Client.Simplified": "2.6.0" + } + }, "Nerdbank.Streams": { "type": "Transitive", "resolved": "2.11.90", diff --git a/util/ReadmeExample/packages.win-x64.lock.json b/util/ReadmeExample/packages.win-x64.lock.json index 8219651..e6e89c7 100644 --- a/util/ReadmeExample/packages.win-x64.lock.json +++ b/util/ReadmeExample/packages.win-x64.lock.json @@ -36,20 +36,14 @@ "System.IO.Hashing": "9.0.3" } }, - "NATS.Net": { + "NATS.Extensions.Microsoft.DependencyInjection": { "type": "Direct", "requested": "[2.6.0, )", "resolved": "2.6.0", - "contentHash": "rE1jwq7HMLMfOscaC5dOh1VSOrkA4a2EeKnehaFuiygo3VC2g9ONae5KsNSEdioOoHlRq6xDG9Wu4qNa+1tuCQ==", + "contentHash": "riwSWcfutHlt3gQQU3wgImjgNNLnS6y/5G5Rj7XEGNnoNCEJvtdVHQyaICHg05ehexLiDf4idJrR/KVTldWD2w==", "dependencies": { - "NATS.Client.Core": "2.6.0", - "NATS.Client.Hosting": "2.6.0", - "NATS.Client.JetStream": "2.6.0", - "NATS.Client.KeyValueStore": "2.6.0", - "NATS.Client.ObjectStore": "2.6.0", - "NATS.Client.Serializers.Json": "2.6.0", - "NATS.Client.Services": "2.6.0", - "NATS.Client.Simplified": "2.6.0" + "Microsoft.Extensions.Hosting.Abstractions": "8.0.0", + "NATS.Net": "2.6.0" } }, "StyleCop.Analyzers": { @@ -837,6 +831,21 @@ "NATS.Client.Serializers.Json": "2.6.0" } }, + "NATS.Net": { + "type": "Transitive", + "resolved": "2.6.0", + "contentHash": "rE1jwq7HMLMfOscaC5dOh1VSOrkA4a2EeKnehaFuiygo3VC2g9ONae5KsNSEdioOoHlRq6xDG9Wu4qNa+1tuCQ==", + "dependencies": { + "NATS.Client.Core": "2.6.0", + "NATS.Client.Hosting": "2.6.0", + "NATS.Client.JetStream": "2.6.0", + "NATS.Client.KeyValueStore": "2.6.0", + "NATS.Client.ObjectStore": "2.6.0", + "NATS.Client.Serializers.Json": "2.6.0", + "NATS.Client.Services": "2.6.0", + "NATS.Client.Simplified": "2.6.0" + } + }, "Nerdbank.Streams": { "type": "Transitive", "resolved": "2.11.90",