From 09fd84cb9e0686e5373ef7eab7c96e543f17778a Mon Sep 17 00:00:00 2001 From: Tobias Kamenicky Date: Fri, 22 Nov 2019 10:44:24 +0100 Subject: [PATCH 1/3] KCL-2975 Review changes & updating readme --- README.md | 10 ++++++---- .../Controllers/WebhooksController.cs | 2 +- .../Caching/CacheHelper.cs | 20 +++++-------------- .../Caching/CacheOptions.cs | 4 ++-- .../Caching/Default/CacheManager.cs | 6 +++--- .../Caching/Webhooks/CacheManager.cs | 4 ++-- .../Kentico.Kontent.Boilerplate/Startup.cs | 19 +++++++++--------- .../Caching/Default/CacheManagerTests.cs | 8 ++++---- .../Caching/ResponseHelper.cs | 2 +- .../Caching/Webhooks/CacheManagerTests.cs | 8 ++++---- 10 files changed, 37 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 727aa96..3ca3020 100644 --- a/README.md +++ b/README.md @@ -86,13 +86,15 @@ Rich text elements in Kentico Kontent can contain links to other content items. ### How to set up webhook-enabled caching -All content retrieved from Kentico Kontent is by default [cached](https://github.com/Kentico/kontent-boilerplate-net/blob/master/src/content/Kentico.Kontent.Boilerplate/Services/CachedDeliveryClient.cs) for 24 hours in a [MemoryCache](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.caching.memorycache) singleton object. You can either change the time by overriding the value of the `CacheTimeoutSeconds` environment variable (e.g. in appsettings.json). Or, if you want your app to immediately clear cache entries of changed content, you can create a webhook in Kentico Kontent for that. +All content retrieved from Kentico Kontent is by default [cached](https://github.com/Kentico/kontent-boilerplate-net/blob/master/src/content/Kentico.Kontent.Boilerplate/Caching/Default/CachingDeliveryClient.cs) in a [MemoryCache](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.caching.memory.memorycache) singleton object. When the retrieved content is stale (newer version exists) the response is cached for 2 seconds by default, otherwise it is cached for 20 seconds. You can change the expiration times in [Startup](https://github.com/Kentico/kontent-boilerplate-net/blob/6fb2b26deecb858f3853d84e29121e3f17b3a291/src/content/Kentico.Kontent.Boilerplate/Startup.cs#L47). -To create the web hook, go to Project settings --> Webhooks --> Create new Webhook. Give it a name (like "Cache invalidation webhook") and the publicly routable URL of your app with `/WebHooks/KenticoKontent` appended (like "https://myapp.azurewebsites.net/WebHooks/KenticoKontent"). Then, copy the API secret and paste it as the `KenticoKontentWebhookSecret` environment variable (secret) into your app's settings. +If you need updated content as soon as possible, you can use another caching strategy where entries are invalidated by webhooks. In order to enable this strategy just switch to another implemented [caching client](https://github.com/Kentico/kontent-boilerplate-net/blob/master/src/content/Kentico.Kontent.Boilerplate/Caching/Webhooks/CachingDeliveryClient.cs) by using `IServiceCollection.AddWebhookInvalidatedCachingClient` extension in [Startup](https://github.com/Kentico/kontent-boilerplate-net/blob/6fb2b26deecb858f3853d84e29121e3f17b3a291/src/content/Kentico.Kontent.Boilerplate/Startup.cs#L53). Also, you need to create a webhook. -![New webhook configuration](https://i.imgur.com/ootVcPZ.png) +To create the webhook, go to Project settings --> Webhooks --> Create new Webhook. Give it a name (like "Cache invalidation webhook") and the publicly routable URL of your app with `/Webhooks/Webhooks` appended (like "https://myapp.azurewebsites.net/Webhooks/Webhooks"). Then, copy the API secret and paste it as the `KenticoKontentWebhookSecret` environment variable (secret) into your app's settings (e.g. appsettings.json). -**Note**: During local development, you can use the [ngrok](https://ngrok.com/) service to route to your workstation. +![New webhook configuration](https://i.imgur.com/TjJ7n5H.png) + +**Note**: During local development, you can use the [ngrok](https://ngrok.com/) service to route to your workstation. Simply start your application locally and run command `ngrok http [port] localhost:[port]` and set the webhook URL to the displayed HTTPS address. **Note**: Speed of the Delivery/Preview API service is already tuned up because the service uses a geo-distributed CDN network for most of the types of requests. Therefore, the main advantage of caching in Kentico Kontent applications is not speed but lowering the amount of requests needed (See [pricing](https://kontent.ai/pricing) for details). diff --git a/src/content/Kentico.Kontent.Boilerplate/Areas/WebHooks/Controllers/WebhooksController.cs b/src/content/Kentico.Kontent.Boilerplate/Areas/WebHooks/Controllers/WebhooksController.cs index 5e62888..3398d7f 100644 --- a/src/content/Kentico.Kontent.Boilerplate/Areas/WebHooks/Controllers/WebhooksController.cs +++ b/src/content/Kentico.Kontent.Boilerplate/Areas/WebHooks/Controllers/WebhooksController.cs @@ -48,7 +48,7 @@ public IActionResult Index([FromBody] WebhookModel model) dependencies.Add(CacheHelper.GetTypesDependencyKey()); } - if (model.Message.Type == "content_type") + if (model.Message.Type.Equals("content_type", StringComparison.Ordinal)) { dependencies.Add(CacheHelper.GetTypesDependencyKey()); } diff --git a/src/content/Kentico.Kontent.Boilerplate/Caching/CacheHelper.cs b/src/content/Kentico.Kontent.Boilerplate/Caching/CacheHelper.cs index c97d5f0..b223657 100644 --- a/src/content/Kentico.Kontent.Boilerplate/Caching/CacheHelper.cs +++ b/src/content/Kentico.Kontent.Boilerplate/Caching/CacheHelper.cs @@ -7,7 +7,7 @@ namespace Kentico.Kontent.Boilerplate.Caching { - public class CacheHelper + public static class CacheHelper { #region Constants @@ -174,7 +174,7 @@ public static IEnumerable GetItemJsonDependencies(JObject response) return dependencies.Count > MAX_DEPENDENCY_ITEMS ? new[] { GetItemsDependencyKey() } - : dependencies.Distinct(); + : dependencies.AsEnumerable(); bool TryExtractCodename(JObject item, out string codename) { @@ -215,7 +215,7 @@ public static IEnumerable GetItemDependencies(dynamic response) return dependencies.Count > MAX_DEPENDENCY_ITEMS ? new[] { GetItemsDependencyKey() } - : dependencies.Distinct(); + : dependencies.AsEnumerable(); } public static IEnumerable GetItemsJsonDependencies(JObject response) @@ -232,16 +232,6 @@ public static IEnumerable GetItemsDependencies(dynamic response) : Enumerable.Empty(); } - public static IEnumerable GetItemsFeedDependencies(DeliveryItemsFeedResponse _) - { - return new[] { GetItemsDependencyKey() }; - } - - public static IEnumerable GetItemsFeedDependencies(DeliveryItemsFeedResponse _) - { - return new[] { GetItemsDependencyKey() }; - } - public static IEnumerable GetTypeJsonDependencies(JObject response) { return response?["system"]?["codename"] != null @@ -334,10 +324,10 @@ private static bool IsItemListingResponse(dynamic response) private static bool IsComponent(JProperty property) { - // Components have 0 on index 14 in its id. + // Components have substring 01 in its id starting on position 14. // xxxxxxxx-xxxx-0xxx-xxxx-xxxxxxxxxxxx var id = property?.Value?["system"]?["id"]?.Value(); - return Guid.TryParse(id, out _) && id?[14] == '0'; + return Guid.TryParse(id, out _) && id.Substring(14, 2).Equals("01", StringComparison.Ordinal); } } } \ No newline at end of file diff --git a/src/content/Kentico.Kontent.Boilerplate/Caching/CacheOptions.cs b/src/content/Kentico.Kontent.Boilerplate/Caching/CacheOptions.cs index 649ae0e..04ce665 100644 --- a/src/content/Kentico.Kontent.Boilerplate/Caching/CacheOptions.cs +++ b/src/content/Kentico.Kontent.Boilerplate/Caching/CacheOptions.cs @@ -4,7 +4,7 @@ namespace Kentico.Kontent.Boilerplate.Caching { public class CacheOptions { - public TimeSpan DefaultTimeout { get; set; } = TimeSpan.FromMinutes(10); - public TimeSpan StaleContentTimeout { get; set; } = TimeSpan.FromSeconds(10); + public TimeSpan DefaultExpiration { get; set; } = TimeSpan.FromMinutes(10); + public TimeSpan StaleContentExpiration { get; set; } = TimeSpan.FromSeconds(10); } } \ No newline at end of file diff --git a/src/content/Kentico.Kontent.Boilerplate/Caching/Default/CacheManager.cs b/src/content/Kentico.Kontent.Boilerplate/Caching/Default/CacheManager.cs index d67eddb..00d4dfc 100644 --- a/src/content/Kentico.Kontent.Boilerplate/Caching/Default/CacheManager.cs +++ b/src/content/Kentico.Kontent.Boilerplate/Caching/Default/CacheManager.cs @@ -50,13 +50,13 @@ public async Task GetOrAddAsync(string key, Func> valueFactory, Fu var valueCacheOptions = new MemoryCacheEntryOptions(); if (value is AbstractResponse ar && ar.HasStaleContent) { - valueCacheOptions.SetAbsoluteExpiration(_cacheOptions.StaleContentTimeout); + valueCacheOptions.SetAbsoluteExpiration(_cacheOptions.StaleContentExpiration); } else { - valueCacheOptions.SetAbsoluteExpiration(_cacheOptions.DefaultTimeout); + valueCacheOptions.SetAbsoluteExpiration(_cacheOptions.DefaultExpiration); } - + return _memoryCache.Set(key, value, valueCacheOptions); } finally diff --git a/src/content/Kentico.Kontent.Boilerplate/Caching/Webhooks/CacheManager.cs b/src/content/Kentico.Kontent.Boilerplate/Caching/Webhooks/CacheManager.cs index ece80a0..1e67b5b 100644 --- a/src/content/Kentico.Kontent.Boilerplate/Caching/Webhooks/CacheManager.cs +++ b/src/content/Kentico.Kontent.Boilerplate/Caching/Webhooks/CacheManager.cs @@ -53,11 +53,11 @@ public async Task GetOrAddAsync(string key, Func> valueFactory, Fu var valueCacheOptions = new MemoryCacheEntryOptions(); if (value is AbstractResponse ar && ar.HasStaleContent) { - valueCacheOptions.SetAbsoluteExpiration(_cacheOptions.StaleContentTimeout); + valueCacheOptions.SetAbsoluteExpiration(_cacheOptions.StaleContentExpiration); } else { - valueCacheOptions.SetSlidingExpiration(_cacheOptions.DefaultTimeout); + valueCacheOptions.SetSlidingExpiration(_cacheOptions.DefaultExpiration); } var dependencies = dependenciesFactory?.Invoke(value) ?? new List(); diff --git a/src/content/Kentico.Kontent.Boilerplate/Startup.cs b/src/content/Kentico.Kontent.Boilerplate/Startup.cs index 8601be3..06de982 100644 --- a/src/content/Kentico.Kontent.Boilerplate/Startup.cs +++ b/src/content/Kentico.Kontent.Boilerplate/Startup.cs @@ -10,7 +10,6 @@ using Microsoft.AspNetCore.Rewrite; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; using Kentico.Kontent.Boilerplate.Caching; namespace Kentico.Kontent.Boilerplate @@ -32,7 +31,7 @@ public void ConfigureServices(IServiceCollection services) // Register the IConfiguration instance which ProjectOptions binds against. services.Configure(Configuration); - + var deliveryOptions = new DeliveryOptions(); Configuration.GetSection(nameof(DeliveryOptions)).Bind(deliveryOptions); @@ -45,16 +44,16 @@ IDeliveryClient BuildBaseClient(IServiceProvider sp) => DeliveryClientBuilder .Build(); // Use cached client version based on the use case - //services.AddCachingClient(BuildBaseClient, options => - //{ - // options.StaleContentTimeout = TimeSpan.FromSeconds(2); - // options.DefaultTimeout = TimeSpan.FromSeconds(20); - //}); - services.AddWebhookInvalidatedCachingClient(BuildBaseClient, options => + services.AddCachingClient(BuildBaseClient, options => { - options.StaleContentTimeout = TimeSpan.FromSeconds(2); - options.DefaultTimeout = TimeSpan.FromHours(24); + options.StaleContentExpiration = TimeSpan.FromSeconds(2); + options.DefaultExpiration = TimeSpan.FromSeconds(20); }); + //services.AddWebhookInvalidatedCachingClient(BuildBaseClient, options => + //{ + // options.StaleContentExpiration = TimeSpan.FromSeconds(2); + // options.DefaultExpiration = TimeSpan.FromHours(24); + //}); HtmlHelperExtensions.ProjectOptions = Configuration.Get(); diff --git a/test/Kentico.Kontent.Boilerplate.Tests/Caching/Default/CacheManagerTests.cs b/test/Kentico.Kontent.Boilerplate.Tests/Caching/Default/CacheManagerTests.cs index dfab18f..c5d27be 100644 --- a/test/Kentico.Kontent.Boilerplate.Tests/Caching/Default/CacheManagerTests.cs +++ b/test/Kentico.Kontent.Boilerplate.Tests/Caching/Default/CacheManagerTests.cs @@ -81,10 +81,10 @@ public async Task GetOrAddAsync_IsNotStaleContent_CachedValueExpiresAfterDefault { const string key = "key"; var value = await GetAbstractResponseInstance(false); - _cacheOptions.DefaultTimeout = TimeSpan.FromMilliseconds(500); + _cacheOptions.DefaultExpiration = TimeSpan.FromMilliseconds(500); await _cacheManager.GetOrAddAsync(key, () => Task.FromResult(value)); - await Task.Delay(_cacheOptions.DefaultTimeout); + await Task.Delay(_cacheOptions.DefaultExpiration); Assert.False(_memoryCache.TryGetValue(key, out _)); } @@ -94,10 +94,10 @@ public async Task GetOrAddAsync_IsStaleContent_CachedValueExpiresAfterStaleConte { const string key = "key"; var value = await GetAbstractResponseInstance(true); - _cacheOptions.StaleContentTimeout = TimeSpan.FromMilliseconds(500); + _cacheOptions.StaleContentExpiration = TimeSpan.FromMilliseconds(500); await _cacheManager.GetOrAddAsync(key, () => Task.FromResult(value)); - await Task.Delay(_cacheOptions.StaleContentTimeout); + await Task.Delay(_cacheOptions.StaleContentExpiration); Assert.False(_memoryCache.TryGetValue(key, out _)); } diff --git a/test/Kentico.Kontent.Boilerplate.Tests/Caching/ResponseHelper.cs b/test/Kentico.Kontent.Boilerplate.Tests/Caching/ResponseHelper.cs index 6ad8144..a37cf4c 100644 --- a/test/Kentico.Kontent.Boilerplate.Tests/Caching/ResponseHelper.cs +++ b/test/Kentico.Kontent.Boilerplate.Tests/Caching/ResponseHelper.cs @@ -80,7 +80,7 @@ public static class ResponseHelper internal static (string codename, object item) CreateComponent() { var id = Guid.NewGuid().ToString(); - id = $"{id.Substring(0, 14)}0{id.Substring(15)}"; + id = $"{id.Substring(0, 14)}01{id.Substring(16)}"; var codename = $"n{id}"; return ( codename, diff --git a/test/Kentico.Kontent.Boilerplate.Tests/Caching/Webhooks/CacheManagerTests.cs b/test/Kentico.Kontent.Boilerplate.Tests/Caching/Webhooks/CacheManagerTests.cs index 456cd36..d84d931 100644 --- a/test/Kentico.Kontent.Boilerplate.Tests/Caching/Webhooks/CacheManagerTests.cs +++ b/test/Kentico.Kontent.Boilerplate.Tests/Caching/Webhooks/CacheManagerTests.cs @@ -151,10 +151,10 @@ public async Task GetOrAddAsync_IsNotStaleContent_CachedValueExpiresAfterDefault { const string key = "key"; var value = await GetAbstractResponseInstance(false); - _cacheOptions.DefaultTimeout = TimeSpan.FromMilliseconds(500); + _cacheOptions.DefaultExpiration = TimeSpan.FromMilliseconds(500); await _cacheManager.GetOrAddAsync(key, () => Task.FromResult(value), null); - await Task.Delay(_cacheOptions.DefaultTimeout); + await Task.Delay(_cacheOptions.DefaultExpiration); Assert.False(_memoryCache.TryGetValue(key, out _)); } @@ -164,10 +164,10 @@ public async Task GetOrAddAsync_IsStaleContent_CachedValueExpiresAfterStaleConte { const string key = "key"; var value = await GetAbstractResponseInstance(true); - _cacheOptions.StaleContentTimeout = TimeSpan.FromMilliseconds(500); + _cacheOptions.StaleContentExpiration = TimeSpan.FromMilliseconds(500); await _cacheManager.GetOrAddAsync(key, () => Task.FromResult(value), null); - await Task.Delay(_cacheOptions.StaleContentTimeout); + await Task.Delay(_cacheOptions.StaleContentExpiration); Assert.False(_memoryCache.TryGetValue(key, out _)); } From 97c0947c2c2d5f0742f489272eda46a64e16107c Mon Sep 17 00:00:00 2001 From: Tobias Kamenicky Date: Mon, 25 Nov 2019 17:00:10 +0100 Subject: [PATCH 2/3] Update README.md & expiration time --- README.md | 6 +++--- src/content/Kentico.Kontent.Boilerplate/Startup.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3ca3020..d5ac3bb 100644 --- a/README.md +++ b/README.md @@ -86,11 +86,11 @@ Rich text elements in Kentico Kontent can contain links to other content items. ### How to set up webhook-enabled caching -All content retrieved from Kentico Kontent is by default [cached](https://github.com/Kentico/kontent-boilerplate-net/blob/master/src/content/Kentico.Kontent.Boilerplate/Caching/Default/CachingDeliveryClient.cs) in a [MemoryCache](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.caching.memory.memorycache) singleton object. When the retrieved content is stale (newer version exists) the response is cached for 2 seconds by default, otherwise it is cached for 20 seconds. You can change the expiration times in [Startup](https://github.com/Kentico/kontent-boilerplate-net/blob/6fb2b26deecb858f3853d84e29121e3f17b3a291/src/content/Kentico.Kontent.Boilerplate/Startup.cs#L47). +All content retrieved from Kentico Kontent is by default [cached](https://github.com/Kentico/kontent-boilerplate-net/blob/master/src/content/Kentico.Kontent.Boilerplate/Caching/Default/CachingDeliveryClient.cs) for 10 minutes in a [MemoryCache](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.caching.memory.memorycache) singleton object. When content is stale (newer version exists) it is cached for 2 seconds. You can change the expiration times in [Startup](https://github.com/Kentico/kontent-boilerplate-net/blob/6fb2b26deecb858f3853d84e29121e3f17b3a291/src/content/Kentico.Kontent.Boilerplate/Startup.cs#L47). -If you need updated content as soon as possible, you can use another caching strategy where entries are invalidated by webhooks. In order to enable this strategy just switch to another implemented [caching client](https://github.com/Kentico/kontent-boilerplate-net/blob/master/src/content/Kentico.Kontent.Boilerplate/Caching/Webhooks/CachingDeliveryClient.cs) by using `IServiceCollection.AddWebhookInvalidatedCachingClient` extension in [Startup](https://github.com/Kentico/kontent-boilerplate-net/blob/6fb2b26deecb858f3853d84e29121e3f17b3a291/src/content/Kentico.Kontent.Boilerplate/Startup.cs#L53). Also, you need to create a webhook. +If displaying outdated content for a limited time is not an option, you need to use another caching strategy and invalidate cached content when a webhook notification about content change is received. To enable this caching strategy just switch to another [caching client](https://github.com/Kentico/kontent-boilerplate-net/blob/master/src/content/Kentico.Kontent.Boilerplate/Caching/Webhooks/CachingDeliveryClient.cs) by using `IServiceCollection.AddWebhookInvalidatedCachingClient` extension in [Startup](https://github.com/Kentico/kontent-boilerplate-net/blob/6fb2b26deecb858f3853d84e29121e3f17b3a291/src/content/Kentico.Kontent.Boilerplate/Startup.cs#L53). -To create the webhook, go to Project settings --> Webhooks --> Create new Webhook. Give it a name (like "Cache invalidation webhook") and the publicly routable URL of your app with `/Webhooks/Webhooks` appended (like "https://myapp.azurewebsites.net/Webhooks/Webhooks"). Then, copy the API secret and paste it as the `KenticoKontentWebhookSecret` environment variable (secret) into your app's settings (e.g. appsettings.json). +Also, you need to [create a webhook](https://docs.kontent.ai/tutorials/develop-apps/integrate/using-webhooks-for-automatic-updates#a-creating-a-webhook). When entering a webhook URL, append a `/Webhooks/Webhooks` path to a publicly available URL address of the application, e.g. `https://myapp.azurewebsites.net/Webhooks/Webhooks`. Finally, copy the API secret and put it into the app settings (usually the appsettings.json) as the `KenticoKontentWebhookSecret` environment variable. ![New webhook configuration](https://i.imgur.com/TjJ7n5H.png) diff --git a/src/content/Kentico.Kontent.Boilerplate/Startup.cs b/src/content/Kentico.Kontent.Boilerplate/Startup.cs index f8d685a..c3d2083 100644 --- a/src/content/Kentico.Kontent.Boilerplate/Startup.cs +++ b/src/content/Kentico.Kontent.Boilerplate/Startup.cs @@ -45,7 +45,7 @@ IDeliveryClient BuildBaseClient(IServiceProvider sp) => DeliveryClientBuilder services.AddCachingClient(BuildBaseClient, options => { options.StaleContentExpiration = TimeSpan.FromSeconds(2); - options.DefaultExpiration = TimeSpan.FromSeconds(20); + options.DefaultExpiration = TimeSpan.FromMinutes(10); }); //services.AddWebhookInvalidatedCachingClient(BuildBaseClient, options => //{ From 1bd8682c3131d8b8ae652bae5e5d3c7ce0e1b379 Mon Sep 17 00:00:00 2001 From: Tobias Kamenicky Date: Thu, 28 Nov 2019 08:07:07 +0100 Subject: [PATCH 3/3] KCL-2975 Minor review changes --- .../Areas/WebHooks/Controllers/WebhooksController.cs | 2 +- .../Kentico.Kontent.Boilerplate/Caching/CacheHelper.cs | 4 ++-- .../Caching/ResponseHelper.cs | 2 ++ 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/content/Kentico.Kontent.Boilerplate/Areas/WebHooks/Controllers/WebhooksController.cs b/src/content/Kentico.Kontent.Boilerplate/Areas/WebHooks/Controllers/WebhooksController.cs index a066e44..ad7d03b 100644 --- a/src/content/Kentico.Kontent.Boilerplate/Areas/WebHooks/Controllers/WebhooksController.cs +++ b/src/content/Kentico.Kontent.Boilerplate/Areas/WebHooks/Controllers/WebhooksController.cs @@ -46,7 +46,7 @@ public IActionResult Index([FromBody] WebhookModel model) dependencies.Add(CacheHelper.GetTypesDependencyKey()); } - if (model.Message.Type.Equals("content_type", StringComparison.Ordinal)) + if (model.Message.Type == "content_type") { dependencies.Add(CacheHelper.GetTypesDependencyKey()); } diff --git a/src/content/Kentico.Kontent.Boilerplate/Caching/CacheHelper.cs b/src/content/Kentico.Kontent.Boilerplate/Caching/CacheHelper.cs index b223657..5a2302e 100644 --- a/src/content/Kentico.Kontent.Boilerplate/Caching/CacheHelper.cs +++ b/src/content/Kentico.Kontent.Boilerplate/Caching/CacheHelper.cs @@ -324,8 +324,8 @@ private static bool IsItemListingResponse(dynamic response) private static bool IsComponent(JProperty property) { - // Components have substring 01 in its id starting on position 14. - // xxxxxxxx-xxxx-0xxx-xxxx-xxxxxxxxxxxx + // Components have substring 01 in its id starting at position 14. + // xxxxxxxx-xxxx-01xx-xxxx-xxxxxxxxxxxx var id = property?.Value?["system"]?["id"]?.Value(); return Guid.TryParse(id, out _) && id.Substring(14, 2).Equals("01", StringComparison.Ordinal); } diff --git a/test/Kentico.Kontent.Boilerplate.Tests/Caching/ResponseHelper.cs b/test/Kentico.Kontent.Boilerplate.Tests/Caching/ResponseHelper.cs index a37cf4c..15ce243 100644 --- a/test/Kentico.Kontent.Boilerplate.Tests/Caching/ResponseHelper.cs +++ b/test/Kentico.Kontent.Boilerplate.Tests/Caching/ResponseHelper.cs @@ -79,6 +79,8 @@ public static class ResponseHelper internal static (string codename, object item) CreateComponent() { + // Components have substring 01 in its id starting at position 14. + // xxxxxxxx-xxxx-01xx-xxxx-xxxxxxxxxxxx var id = Guid.NewGuid().ToString(); id = $"{id.Substring(0, 14)}01{id.Substring(16)}"; var codename = $"n{id}";