From 3e6aec86a81d46be2e4136c6629a3438c9623230 Mon Sep 17 00:00:00 2001 From: dudu Date: Sat, 6 Jul 2019 15:57:37 +0800 Subject: [PATCH 1/2] Introduce IMemcachedClient and MemcachedClient --- ...yimMemcachedServiceCollectionExtensions.cs | 27 +- Enyim.Caching/IMemcachedClientT.cs | 10 + Enyim.Caching/MemcachedClient.cs | 6 +- Enyim.Caching/MemcachedClientT.cs | 288 ++++++++++++++++++ .../HomeControllerTests.cs | 8 + SampleWebApp/Controllers/HomeController.cs | 12 + SampleWebApp/Models/PostBody.cs | 11 + SampleWebApp/Startup.cs | 2 + SampleWebApp/appsettings.json | 9 + 9 files changed, 367 insertions(+), 6 deletions(-) create mode 100644 Enyim.Caching/IMemcachedClientT.cs create mode 100644 Enyim.Caching/MemcachedClientT.cs create mode 100644 SampleWebApp/Models/PostBody.cs diff --git a/Enyim.Caching/EnyimMemcachedServiceCollectionExtensions.cs b/Enyim.Caching/EnyimMemcachedServiceCollectionExtensions.cs index 60dcb804..8ea2d131 100644 --- a/Enyim.Caching/EnyimMemcachedServiceCollectionExtensions.cs +++ b/Enyim.Caching/EnyimMemcachedServiceCollectionExtensions.cs @@ -5,6 +5,8 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using System; namespace Microsoft.Extensions.DependencyInjection @@ -49,7 +51,7 @@ public static IServiceCollection AddEnyimMemcached(this IServiceCollection servi throw new ArgumentNullException(nameof(configurationSection)); } - if(!configurationSection.Exists()) + if (!configurationSection.Exists()) { throw new ArgumentNullException($"{configurationSection.Key} in appsettings.json"); } @@ -92,6 +94,27 @@ private static IServiceCollection AddEnyimMemcachedInternal(IServiceCollection s services.AddSingleton(factory => factory.GetService()); return services; - } + } + + public static IServiceCollection AddEnyimMemcached( + this IServiceCollection services, + IConfiguration configuration, + string sectionKey) + { + services.AddOptions(); + services.Configure(sectionKey, configuration.GetSection(sectionKey)); + services.TryAddSingleton(); + services.TryAddSingleton(); + + services.AddSingleton>(sp => + { + var loggerFactory = sp.GetRequiredService(); + var options = sp.GetRequiredService>(); + var conf = new MemcachedClientConfiguration(loggerFactory, options.Get(sectionKey)); + return new MemcachedClient(loggerFactory, conf); + }); + + return services; + } } } diff --git a/Enyim.Caching/IMemcachedClientT.cs b/Enyim.Caching/IMemcachedClientT.cs new file mode 100644 index 00000000..083e6964 --- /dev/null +++ b/Enyim.Caching/IMemcachedClientT.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Enyim.Caching +{ + public interface IMemcachedClient : IMemcachedClient + { + } +} diff --git a/Enyim.Caching/MemcachedClient.cs b/Enyim.Caching/MemcachedClient.cs index a6a1aa10..4eead3d5 100755 --- a/Enyim.Caching/MemcachedClient.cs +++ b/Enyim.Caching/MemcachedClient.cs @@ -42,11 +42,9 @@ public partial class MemcachedClient : IMemcachedClient, IMemcachedResultsClient protected IMemcachedKeyTransformer KeyTransformer { get { return this.keyTransformer; } } protected ITranscoder Transcoder { get { return this.transcoder; } } - public MemcachedClient( - ILoggerFactory loggerFactor, - IMemcachedClientConfiguration configuration) + public MemcachedClient(ILoggerFactory loggerFactory, IMemcachedClientConfiguration configuration) { - _logger = loggerFactor.CreateLogger(); + _logger = loggerFactory.CreateLogger(); if (configuration == null) { diff --git a/Enyim.Caching/MemcachedClientT.cs b/Enyim.Caching/MemcachedClientT.cs new file mode 100644 index 00000000..2b870789 --- /dev/null +++ b/Enyim.Caching/MemcachedClientT.cs @@ -0,0 +1,288 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; +using Enyim.Caching.Configuration; +using Enyim.Caching.Memcached; +using Enyim.Caching.Memcached.Results; +using Microsoft.Extensions.Logging; + +namespace Enyim.Caching +{ + public class MemcachedClient : IMemcachedClient + { + private readonly IMemcachedClient _memcachedClient; + + public event Action NodeFailed; + + public MemcachedClient(ILoggerFactory loggerFactory, IMemcachedClientConfiguration configuration) + { + _memcachedClient = new MemcachedClient(loggerFactory, configuration); + } + + public bool Add(string key, object value, int cacheSeconds) + { + return _memcachedClient.Add(key, value, cacheSeconds); + } + + public Task AddAsync(string key, object value, int cacheSeconds) + { + return _memcachedClient.AddAsync(key, value, cacheSeconds); + } + + public bool Append(string key, ArraySegment data) + { + return _memcachedClient.Append(key, data); + } + + public CasResult Append(string key, ulong cas, ArraySegment data) + { + return _memcachedClient.Append(key, cas, data); + } + + public CasResult Cas(StoreMode mode, string key, object value) + { + return _memcachedClient.Cas(mode, key, value); + } + + public CasResult Cas(StoreMode mode, string key, object value, ulong cas) + { + return _memcachedClient.Cas(mode, key, value, cas); + } + + public CasResult Cas(StoreMode mode, string key, object value, DateTime expiresAt, ulong cas) + { + return _memcachedClient.Cas(mode, key, value, expiresAt, cas); + } + + public CasResult Cas(StoreMode mode, string key, object value, TimeSpan validFor, ulong cas) + { + return _memcachedClient.Cas(mode, key, value, validFor, cas); + } + + public ulong Decrement(string key, ulong defaultValue, ulong delta) + { + return _memcachedClient.Decrement(key, defaultValue, delta); + } + + public ulong Decrement(string key, ulong defaultValue, ulong delta, DateTime expiresAt) + { + return _memcachedClient.Decrement(key, defaultValue, delta, expiresAt); + } + + public ulong Decrement(string key, ulong defaultValue, ulong delta, TimeSpan validFor) + { + return _memcachedClient.Decrement(key, defaultValue, delta, validFor); + } + + public CasResult Decrement(string key, ulong defaultValue, ulong delta, ulong cas) + { + return _memcachedClient.Decrement(key, defaultValue, delta, cas); + } + + public CasResult Decrement(string key, ulong defaultValue, ulong delta, DateTime expiresAt, ulong cas) + { + return _memcachedClient.Decrement(key, defaultValue, delta, expiresAt, cas); + } + + public CasResult Decrement(string key, ulong defaultValue, ulong delta, TimeSpan validFor, ulong cas) + { + return _memcachedClient.Decrement(key, defaultValue, delta, validFor, cas); + } + + public void Dispose() + { + _memcachedClient.Dispose(); + } + + public void FlushAll() + { + _memcachedClient.FlushAll(); + } + + public Task FlushAllAsync() + { + return _memcachedClient.FlushAllAsync(); + } + + public object Get(string key) + { + return _memcachedClient.Get(key); + } + + public T1 Get(string key) + { + return _memcachedClient.Get(key); + } + + public IDictionary Get(IEnumerable keys) + { + return _memcachedClient.Get(keys); + } + + public Task> GetAsync(string key) + { + return _memcachedClient.GetAsync(key); + } + + public Task> GetAsync(IEnumerable keys) + { + return _memcachedClient.GetAsync(keys); + } + + public Task GetValueAsync(string key) + { + return _memcachedClient.GetValueAsync(key); + } + + public Task GetValueOrCreateAsync(string key, int cacheSeconds, Func> generator) + { + return _memcachedClient.GetValueOrCreateAsync(key, cacheSeconds, generator); + } + + public CasResult GetWithCas(string key) + { + return _memcachedClient.GetWithCas(key); + } + + public CasResult GetWithCas(string key) + { + return _memcachedClient.GetWithCas(key); + } + + public IDictionary> GetWithCas(IEnumerable keys) + { + return _memcachedClient.GetWithCas(keys); + } + + public Task>> GetWithCasAsync(IEnumerable keys) + { + return _memcachedClient.GetWithCasAsync(keys); + } + + public ulong Increment(string key, ulong defaultValue, ulong delta) + { + return _memcachedClient.Increment(key, defaultValue, delta); + } + + public ulong Increment(string key, ulong defaultValue, ulong delta, DateTime expiresAt) + { + return _memcachedClient.Increment(key, defaultValue, delta, expiresAt); + } + + public ulong Increment(string key, ulong defaultValue, ulong delta, TimeSpan validFor) + { + return _memcachedClient.Increment(key, defaultValue, delta, validFor); + } + + public CasResult Increment(string key, ulong defaultValue, ulong delta, ulong cas) + { + return _memcachedClient.Increment(key, defaultValue, delta, cas); + } + + public CasResult Increment(string key, ulong defaultValue, ulong delta, DateTime expiresAt, ulong cas) + { + return _memcachedClient.Increment(key, defaultValue, delta, expiresAt, cas); + } + + public CasResult Increment(string key, ulong defaultValue, ulong delta, TimeSpan validFor, ulong cas) + { + return _memcachedClient.Increment(key, defaultValue, delta, validFor, cas); + } + + public bool Prepend(string key, ArraySegment data) + { + return _memcachedClient.Prepend(key, data); + } + + public CasResult Prepend(string key, ulong cas, ArraySegment data) + { + return _memcachedClient.Prepend(key, cas, data); + } + + public bool Remove(string key) + { + return _memcachedClient.Remove(key); + } + + public Task RemoveAsync(string key) + { + return _memcachedClient.RemoveAsync(key); + } + + public bool Replace(string key, object value, int cacheSeconds) + { + return _memcachedClient.Replace(key, value, cacheSeconds); + } + + public Task ReplaceAsync(string key, object value, int cacheSeconds) + { + return _memcachedClient.ReplaceAsync(key, value, cacheSeconds); + } + + public bool Set(string key, object value, int cacheSeconds) + { + return _memcachedClient.Set(key, value, cacheSeconds); + } + + public Task SetAsync(string key, object value, int cacheSeconds) + { + return _memcachedClient.SetAsync(key, value, cacheSeconds); + } + + public ServerStats Stats() + { + return _memcachedClient.Stats(); + } + + public ServerStats Stats(string type) + { + return _memcachedClient.Stats(type); + } + + public bool Store(StoreMode mode, string key, object value) + { + return _memcachedClient.Store(mode, key, value); + } + + public bool Store(StoreMode mode, string key, object value, DateTime expiresAt) + { + return _memcachedClient.Store(mode, key, value, expiresAt); + } + + public bool Store(StoreMode mode, string key, object value, TimeSpan validFor) + { + return _memcachedClient.Store(mode, key, value, validFor); + } + + public Task StoreAsync(StoreMode mode, string key, object value, DateTime expiresAt) + { + return _memcachedClient.StoreAsync(mode, key, value, expiresAt); + } + + public Task StoreAsync(StoreMode mode, string key, object value, TimeSpan validFor) + { + return _memcachedClient.StoreAsync(mode, key, value, validFor); + } + + public Task TouchAsync(string key, DateTime expiresAt) + { + return _memcachedClient.TouchAsync(key, expiresAt); + } + + public Task TouchAsync(string key, TimeSpan validFor) + { + return _memcachedClient.TouchAsync(key, validFor); + } + + public bool TryGet(string key, out object value) + { + return _memcachedClient.TryGet(key, out value); + } + + public bool TryGetWithCas(string key, out CasResult value) + { + return _memcachedClient.TryGetWithCas(key, out value); + } + } +} diff --git a/SampleWebApp.IntegrationTests/HomeControllerTests.cs b/SampleWebApp.IntegrationTests/HomeControllerTests.cs index d343ed67..a82dbdd8 100644 --- a/SampleWebApp.IntegrationTests/HomeControllerTests.cs +++ b/SampleWebApp.IntegrationTests/HomeControllerTests.cs @@ -37,5 +37,13 @@ public async Task HomeController_Index() await memcachedClient.RemoveAsync(HomeController.CacheKey); } + + [Fact] + public async Task Get_postbody_from_cache_ok() + { + var httpClient = _factory.CreateClient(); + var response = await httpClient.GetAsync("/home/postbody"); + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } } } diff --git a/SampleWebApp/Controllers/HomeController.cs b/SampleWebApp/Controllers/HomeController.cs index 961f17ed..d6f57691 100644 --- a/SampleWebApp/Controllers/HomeController.cs +++ b/SampleWebApp/Controllers/HomeController.cs @@ -13,16 +13,20 @@ namespace Enyim.Caching.SampleWebApp.Controllers public class HomeController : Controller { private readonly IMemcachedClient _memcachedClient; + readonly IMemcachedClient _postbodyMemcachedClient; private readonly IBlogPostService _blogPostService; private readonly ILogger _logger; public static readonly string CacheKey = "blogposts-recent"; + public static readonly string PostbodyCacheKey = "postbody"; public HomeController( IMemcachedClient memcachedClient, + IMemcachedClient postbodyMemcachedClient, IBlogPostService blogPostService, ILoggerFactory loggerFactory) { _memcachedClient = memcachedClient; + _postbodyMemcachedClient = postbodyMemcachedClient; _blogPostService = blogPostService; _logger = loggerFactory.CreateLogger(); } @@ -41,5 +45,13 @@ public async Task Index() return Ok(posts); } + + public async Task Postbody() + { + var postbody = (await _blogPostService.GetRecent(10)).First()?.Body; + await _postbodyMemcachedClient.AddAsync(PostbodyCacheKey, postbody, 10); + var result = await _postbodyMemcachedClient.GetAsync(PostbodyCacheKey); + return result.Success ? Ok() : StatusCode(500); + } } } diff --git a/SampleWebApp/Models/PostBody.cs b/SampleWebApp/Models/PostBody.cs new file mode 100644 index 00000000..5c2aee27 --- /dev/null +++ b/SampleWebApp/Models/PostBody.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Enyim.Caching.SampleWebApp.Models +{ + public class PostBody + { + } +} diff --git a/SampleWebApp/Startup.cs b/SampleWebApp/Startup.cs index 2dab5d4c..d8f99b06 100644 --- a/SampleWebApp/Startup.cs +++ b/SampleWebApp/Startup.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using Enyim.Caching; +using Enyim.Caching.SampleWebApp.Models; using Enyim.Caching.SampleWebApp.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; @@ -26,6 +27,7 @@ public Startup(IConfiguration configuration) public void ConfigureServices(IServiceCollection services) { services.AddEnyimMemcached(); + services.AddEnyimMemcached(Configuration, "postbodyMemcached"); //services.AddEnyimMemcached(Configuration); //services.AddEnyimMemcached(Configuration, "enyimMemcached"); //services.AddEnyimMemcached(Configuration.GetSection("enyimMemcached")); diff --git a/SampleWebApp/appsettings.json b/SampleWebApp/appsettings.json index 9211fe45..ca64a6dd 100644 --- a/SampleWebApp/appsettings.json +++ b/SampleWebApp/appsettings.json @@ -28,6 +28,15 @@ //} }, + "postbodyMemcached": { + "Servers": [ + { + "Address": "memcached", + "Port": 11211 + } + ] + }, + "Logging": { "IncludeScopes": false, "LogLevel": { From efba5abd9b06d86992601c9cd44aa0a2a95b82e9 Mon Sep 17 00:00:00 2001 From: dudu Date: Sun, 7 Jul 2019 11:54:18 +0800 Subject: [PATCH 2/2] Add a missing `private` --- SampleWebApp/Controllers/HomeController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SampleWebApp/Controllers/HomeController.cs b/SampleWebApp/Controllers/HomeController.cs index d6f57691..01ecc296 100644 --- a/SampleWebApp/Controllers/HomeController.cs +++ b/SampleWebApp/Controllers/HomeController.cs @@ -13,7 +13,7 @@ namespace Enyim.Caching.SampleWebApp.Controllers public class HomeController : Controller { private readonly IMemcachedClient _memcachedClient; - readonly IMemcachedClient _postbodyMemcachedClient; + private readonly IMemcachedClient _postbodyMemcachedClient; private readonly IBlogPostService _blogPostService; private readonly ILogger _logger; public static readonly string CacheKey = "blogposts-recent";